summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/obsolete/dv13949
-rw-r--r--Documentation/ABI/removed/dv139414
-rw-r--r--Documentation/ABI/removed/raw139415
-rw-r--r--Documentation/ABI/removed/raw1394_legacy_isochronous16
-rw-r--r--Documentation/ABI/removed/video139416
-rw-r--r--Documentation/ABI/testing/sysfs-devices-system-ibm-rtl22
-rw-r--r--Documentation/feature-removal-schedule.txt10
-rw-r--r--MAINTAINERS4
-rw-r--r--arch/arm/mach-ux500/board-mop500.c129
-rw-r--r--arch/arm/mach-ux500/clock.c1
-rw-r--r--arch/arm/mach-ux500/devices-db8500.c20
-rw-r--r--arch/arm/mach-ux500/include/mach/devices.h1
-rw-r--r--arch/arm/mach-ux500/pins-db8500.h32
-rw-r--r--arch/arm/plat-nomadik/include/plat/ske.h50
-rw-r--r--arch/arm/plat-omap/include/plat/omap4-keypad.h14
-rw-r--r--arch/m68k/include/asm/cacheflush_no.h2
-rw-r--r--arch/m68k/include/asm/coldfire.h4
-rw-r--r--arch/m68k/include/asm/gpio.h7
-rw-r--r--arch/m68k/include/asm/m548xgpt.h88
-rw-r--r--arch/m68k/include/asm/m548xsim.h55
-rw-r--r--arch/m68k/include/asm/mcfcache.h2
-rw-r--r--arch/m68k/include/asm/mcfsim.h2
-rw-r--r--arch/m68k/include/asm/mcfslt.h44
-rw-r--r--arch/m68k/include/asm/mcfuart.h9
-rw-r--r--arch/m68k/kernel/asm-offsets.c12
-rw-r--r--arch/m68knommu/Kconfig11
-rw-r--r--arch/m68knommu/Makefile3
-rw-r--r--arch/m68knommu/kernel/.gitignore1
-rw-r--r--arch/m68knommu/kernel/asm-offsets.c11
-rw-r--r--arch/m68knommu/kernel/ptrace.c47
-rw-r--r--arch/m68knommu/kernel/setup.c3
-rw-r--r--arch/m68knommu/kernel/time.c13
-rw-r--r--arch/m68knommu/kernel/traps.c26
-rw-r--r--arch/m68knommu/platform/5206/Makefile4
-rw-r--r--arch/m68knommu/platform/5206e/Makefile4
-rw-r--r--arch/m68knommu/platform/520x/Makefile4
-rw-r--r--arch/m68knommu/platform/523x/Makefile4
-rw-r--r--arch/m68knommu/platform/5249/Makefile4
-rw-r--r--arch/m68knommu/platform/5272/Makefile4
-rw-r--r--arch/m68knommu/platform/5272/config.c16
-rw-r--r--arch/m68knommu/platform/5272/intc.c60
-rw-r--r--arch/m68knommu/platform/527x/Makefile4
-rw-r--r--arch/m68knommu/platform/528x/Makefile4
-rw-r--r--arch/m68knommu/platform/5307/Makefile4
-rw-r--r--arch/m68knommu/platform/532x/Makefile4
-rw-r--r--arch/m68knommu/platform/5407/Makefile4
-rw-r--r--arch/m68knommu/platform/548x/Makefile18
-rw-r--r--arch/m68knommu/platform/548x/config.c115
-rw-r--r--arch/m68knommu/platform/68328/entry.S36
-rw-r--r--arch/m68knommu/platform/68328/head-de2.S6
-rw-r--r--arch/m68knommu/platform/68328/head-ram.S27
-rw-r--r--arch/m68knommu/platform/68328/ints.c6
-rw-r--r--arch/m68knommu/platform/68360/entry.S13
-rw-r--r--arch/m68knommu/platform/68360/ints.c6
-rw-r--r--arch/m68knommu/platform/68VZ328/config.c5
-rw-r--r--arch/m68knommu/platform/coldfire/Makefile5
-rw-r--r--arch/m68knommu/platform/coldfire/entry.S4
-rw-r--r--arch/m68knommu/platform/coldfire/intc-2.c53
-rw-r--r--arch/m68knommu/platform/coldfire/intc-simr.c10
-rw-r--r--arch/m68knommu/platform/coldfire/intc.c8
-rw-r--r--arch/m68knommu/platform/coldfire/sltimers.c145
-rw-r--r--arch/microblaze/kernel/prom.c5
-rw-r--r--arch/mips/Kconfig7
-rw-r--r--arch/mips/include/asm/irq.h5
-rw-r--r--arch/mips/include/asm/prom.h31
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/kernel/mips-mt-fpaff.c2
-rw-r--r--arch/mips/kernel/prom.c112
-rw-r--r--arch/mips/kernel/setup.c2
-rw-r--r--arch/powerpc/kernel/ibmebus.c11
-rw-r--r--arch/powerpc/kernel/legacy_serial.c22
-rw-r--r--arch/powerpc/kernel/prom.c12
-rw-r--r--arch/sh/Kconfig6
-rw-r--r--arch/sh/boards/Kconfig18
-rw-r--r--arch/sh/boards/Makefile2
-rw-r--r--arch/sh/boards/board-sh2007.c133
-rw-r--r--arch/sh/boards/board-sh7757lcr.c374
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c6
-rw-r--r--arch/sh/boards/mach-sdk7786/Makefile5
-rw-r--r--arch/sh/boards/mach-sdk7786/gpio.c49
-rw-r--r--arch/sh/boards/mach-sdk7786/setup.c54
-rw-r--r--arch/sh/boards/mach-sdk7786/sram.c72
-rw-r--r--arch/sh/boards/mach-x3proto/Makefile2
-rw-r--r--arch/sh/boards/mach-x3proto/gpio.c135
-rw-r--r--arch/sh/boards/mach-x3proto/ilsel.c18
-rw-r--r--arch/sh/boards/mach-x3proto/setup.c132
-rw-r--r--arch/sh/boot/compressed/head_32.S4
-rw-r--r--arch/sh/cchips/hd6446x/Makefile2
-rw-r--r--arch/sh/configs/ap325rxa_defconfig1
-rw-r--r--arch/sh/configs/cayman_defconfig1
-rw-r--r--arch/sh/configs/dreamcast_defconfig1
-rw-r--r--arch/sh/configs/ecovec24-romimage_defconfig1
-rw-r--r--arch/sh/configs/edosk7760_defconfig1
-rw-r--r--arch/sh/configs/espt_defconfig1
-rw-r--r--arch/sh/configs/hp6xx_defconfig1
-rw-r--r--arch/sh/configs/kfr2r09-romimage_defconfig1
-rw-r--r--arch/sh/configs/kfr2r09_defconfig1
-rw-r--r--arch/sh/configs/landisk_defconfig1
-rw-r--r--arch/sh/configs/lboxre2_defconfig1
-rw-r--r--arch/sh/configs/magicpanelr2_defconfig1
-rw-r--r--arch/sh/configs/microdev_defconfig1
-rw-r--r--arch/sh/configs/migor_defconfig1
-rw-r--r--arch/sh/configs/polaris_defconfig1
-rw-r--r--arch/sh/configs/r7780mp_defconfig1
-rw-r--r--arch/sh/configs/r7785rp_defconfig1
-rw-r--r--arch/sh/configs/rts7751r2d1_defconfig1
-rw-r--r--arch/sh/configs/rts7751r2dplus_defconfig1
-rw-r--r--arch/sh/configs/sdk7780_defconfig1
-rw-r--r--arch/sh/configs/se7343_defconfig1
-rw-r--r--arch/sh/configs/se7712_defconfig1
-rw-r--r--arch/sh/configs/se7721_defconfig1
-rw-r--r--arch/sh/configs/se7722_defconfig1
-rw-r--r--arch/sh/configs/se7724_defconfig1
-rw-r--r--arch/sh/configs/se7750_defconfig1
-rw-r--r--arch/sh/configs/se7751_defconfig1
-rw-r--r--arch/sh/configs/se7780_defconfig1
-rw-r--r--arch/sh/configs/sh03_defconfig1
-rw-r--r--arch/sh/configs/sh2007_defconfig212
-rw-r--r--arch/sh/configs/sh7710voipgw_defconfig1
-rw-r--r--arch/sh/configs/sh7757lcr_defconfig85
-rw-r--r--arch/sh/configs/sh7763rdp_defconfig1
-rw-r--r--arch/sh/configs/sh7785lcr_defconfig1
-rw-r--r--arch/sh/configs/shx3_defconfig1
-rw-r--r--arch/sh/configs/snapgear_defconfig1
-rw-r--r--arch/sh/configs/systemh_defconfig1
-rw-r--r--arch/sh/configs/titan_defconfig1
-rw-r--r--arch/sh/configs/ul2_defconfig1
-rw-r--r--arch/sh/drivers/dma/dma-api.c4
-rw-r--r--arch/sh/drivers/pci/Makefile1
-rw-r--r--arch/sh/drivers/pci/fixups-sdk7786.c67
-rw-r--r--arch/sh/drivers/pci/ops-sh4.c11
-rw-r--r--arch/sh/drivers/pci/ops-sh7786.c69
-rw-r--r--arch/sh/drivers/pci/pci-sh7751.c2
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.c2
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.h6
-rw-r--r--arch/sh/drivers/pci/pci.c43
-rw-r--r--arch/sh/drivers/pci/pcie-sh7786.c251
-rw-r--r--arch/sh/drivers/pci/pcie-sh7786.h56
-rw-r--r--arch/sh/include/asm/Kbuild2
-rw-r--r--arch/sh/include/asm/elf.h27
-rw-r--r--arch/sh/include/asm/fixmap.h4
-rw-r--r--arch/sh/include/asm/gpio.h6
-rw-r--r--arch/sh/include/asm/irq.h2
-rw-r--r--arch/sh/include/asm/kprobes.h1
-rw-r--r--arch/sh/include/asm/pci.h2
-rw-r--r--arch/sh/include/asm/processor_32.h3
-rw-r--r--arch/sh/include/asm/processor_64.h3
-rw-r--r--arch/sh/include/asm/ptrace.h169
-rw-r--r--arch/sh/include/asm/ptrace_32.h83
-rw-r--r--arch/sh/include/asm/ptrace_64.h20
-rw-r--r--arch/sh/include/asm/sizes.h1
-rw-r--r--arch/sh/include/asm/sram.h38
-rw-r--r--arch/sh/include/asm/system.h2
-rw-r--r--arch/sh/include/asm/system_32.h15
-rw-r--r--arch/sh/include/asm/tlbflush.h2
-rw-r--r--arch/sh/include/asm/unistd_32.h27
-rw-r--r--arch/sh/include/asm/unistd_64.h5
-rw-r--r--arch/sh/include/cpu-sh3/cpu/mmu_context.h1
-rw-r--r--arch/sh/include/cpu-sh4/cpu/freq.h4
-rw-r--r--arch/sh/include/cpu-sh4/cpu/sh7757.h301
-rw-r--r--arch/sh/include/cpu-sh4/cpu/shx3.h64
-rw-r--r--arch/sh/include/mach-common/mach/sh2007.h117
-rw-r--r--arch/sh/include/mach-sdk7786/mach/fpga.h26
-rw-r--r--arch/sh/include/mach-x3proto/mach/hardware.h12
-rw-r--r--arch/sh/include/mach-x3proto/mach/ilsel.h (renamed from arch/sh/include/asm/ilsel.h)0
-rw-r--r--arch/sh/kernel/Makefile8
-rw-r--r--arch/sh/kernel/clkdev.c4
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile5
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7757.c199
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-shx3.c225
-rw-r--r--arch/sh/kernel/cpu/sh4a/intc-shx3.c34
-rw-r--r--arch/sh/kernel/cpu/sh4a/perf_event.c20
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c1582
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-shx3.c587
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7724.c66
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7757.c222
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7786.c126
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c42
-rw-r--r--arch/sh/kernel/head_32.S2
-rw-r--r--arch/sh/kernel/io_trapped.c2
-rw-r--r--arch/sh/kernel/irq.c2
-rw-r--r--arch/sh/kernel/kdebugfs.c16
-rw-r--r--arch/sh/kernel/kprobes.c100
-rw-r--r--arch/sh/kernel/ptrace.c33
-rw-r--r--arch/sh/kernel/ptrace_32.c27
-rw-r--r--arch/sh/kernel/ptrace_64.c88
-rw-r--r--arch/sh/kernel/reboot.c4
-rw-r--r--arch/sh/kernel/setup.c22
-rw-r--r--arch/sh/kernel/syscalls_32.S22
-rw-r--r--arch/sh/kernel/syscalls_64.S3
-rw-r--r--arch/sh/kernel/traps_32.c29
-rw-r--r--arch/sh/kernel/traps_64.c11
-rw-r--r--arch/sh/lib/Makefile2
-rw-r--r--arch/sh/math-emu/math.c3
-rw-r--r--arch/sh/mm/Kconfig4
-rw-r--r--arch/sh/mm/Makefile3
-rw-r--r--arch/sh/mm/asids-debugfs.c2
-rw-r--r--arch/sh/mm/cache-debugfs.c10
-rw-r--r--arch/sh/mm/consistent.c3
-rw-r--r--arch/sh/mm/init.c52
-rw-r--r--arch/sh/mm/nommu.c4
-rw-r--r--arch/sh/mm/pmb.c35
-rw-r--r--arch/sh/mm/sram.c34
-rw-r--r--arch/sh/mm/tlb-debugfs.c11
-rw-r--r--arch/sh/mm/tlbflush_32.c16
-rw-r--r--arch/sh/mm/tlbflush_64.c5
-rw-r--r--arch/sh/tools/mach-types2
-rw-r--r--arch/sparc/Kconfig1
-rw-r--r--arch/sparc/include/asm/Kbuild1
-rw-r--r--arch/sparc/include/asm/floppy_32.h3
-rw-r--r--arch/sparc/include/asm/openprom.h16
-rw-r--r--arch/sparc/include/asm/oplib_32.h44
-rw-r--r--arch/sparc/include/asm/oplib_64.h39
-rw-r--r--arch/sparc/include/asm/prom.h5
-rw-r--r--arch/sparc/kernel/auxio_32.c4
-rw-r--r--arch/sparc/kernel/btext.c4
-rw-r--r--arch/sparc/kernel/devices.c23
-rw-r--r--arch/sparc/kernel/leon_kernel.c2
-rw-r--r--arch/sparc/kernel/pcic.c4
-rw-r--r--arch/sparc/kernel/prom.h6
-rw-r--r--arch/sparc/kernel/prom_common.c202
-rw-r--r--arch/sparc/kernel/setup_64.c2
-rw-r--r--arch/sparc/kernel/starfire.c2
-rw-r--r--arch/sparc/kernel/tadpole.c2
-rw-r--r--arch/sparc/mm/init_64.c2
-rw-r--r--arch/sparc/mm/srmmu.c8
-rw-r--r--arch/sparc/mm/sun4c.c2
-rw-r--r--arch/sparc/prom/init_32.c2
-rw-r--r--arch/sparc/prom/init_64.c4
-rw-r--r--arch/sparc/prom/memory.c3
-rw-r--r--arch/sparc/prom/misc_64.c6
-rw-r--r--arch/sparc/prom/ranges.c6
-rw-r--r--arch/sparc/prom/tree_32.c58
-rw-r--r--arch/sparc/prom/tree_64.c62
-rw-r--r--arch/x86/include/asm/olpc.h2
-rw-r--r--block/blk-core.c24
-rw-r--r--block/blk-merge.c2
-rw-r--r--block/blk.h4
-rw-r--r--block/genhd.c14
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/base/platform.c1
-rw-r--r--drivers/block/xsysace.c3
-rw-r--r--drivers/char/keyboard.c31
-rw-r--r--drivers/char/sysrq.c15
-rw-r--r--drivers/clocksource/sh_cmt.c12
-rw-r--r--drivers/firewire/Kconfig5
-rw-r--r--drivers/firewire/Makefile1
-rw-r--r--drivers/firewire/init_ohci1394_dma.c (renamed from drivers/ieee1394/init_ohci1394_dma.c)76
-rw-r--r--drivers/gpio/xilinx_gpio.c6
-rw-r--r--drivers/hid/hid-core.c5
-rw-r--r--drivers/hid/hid-ids.h4
-rw-r--r--drivers/hid/hid-input.c108
-rw-r--r--drivers/hwmon/Kconfig20
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-sh7760.c4
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c23
-rw-r--r--drivers/ieee1394/Kconfig182
-rw-r--r--drivers/ieee1394/Makefile18
-rw-r--r--drivers/ieee1394/config_roms.c194
-rw-r--r--drivers/ieee1394/config_roms.h19
-rw-r--r--drivers/ieee1394/csr.c843
-rw-r--r--drivers/ieee1394/csr.h99
-rw-r--r--drivers/ieee1394/csr1212.c1467
-rw-r--r--drivers/ieee1394/csr1212.h383
-rw-r--r--drivers/ieee1394/dma.c289
-rw-r--r--drivers/ieee1394/dma.h89
-rw-r--r--drivers/ieee1394/dv1394-private.h587
-rw-r--r--drivers/ieee1394/dv1394.c2584
-rw-r--r--drivers/ieee1394/dv1394.h305
-rw-r--r--drivers/ieee1394/eth1394.c1720
-rw-r--r--drivers/ieee1394/eth1394.h234
-rw-r--r--drivers/ieee1394/highlevel.c691
-rw-r--r--drivers/ieee1394/highlevel.h141
-rw-r--r--drivers/ieee1394/hosts.c249
-rw-r--r--drivers/ieee1394/hosts.h201
-rw-r--r--drivers/ieee1394/ieee1394-ioctl.h106
-rw-r--r--drivers/ieee1394/ieee1394.h220
-rw-r--r--drivers/ieee1394/ieee1394_core.c1380
-rw-r--r--drivers/ieee1394/ieee1394_core.h172
-rw-r--r--drivers/ieee1394/ieee1394_hotplug.h19
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c595
-rw-r--r--drivers/ieee1394/ieee1394_transactions.h40
-rw-r--r--drivers/ieee1394/ieee1394_types.h69
-rw-r--r--drivers/ieee1394/iso.c568
-rw-r--r--drivers/ieee1394/iso.h195
-rw-r--r--drivers/ieee1394/nodemgr.c1901
-rw-r--r--drivers/ieee1394/nodemgr.h186
-rw-r--r--drivers/ieee1394/ohci1394.c3590
-rw-r--r--drivers/ieee1394/ohci1394.h453
-rw-r--r--drivers/ieee1394/pcilynx.c1554
-rw-r--r--drivers/ieee1394/pcilynx.h468
-rw-r--r--drivers/ieee1394/raw1394-private.h81
-rw-r--r--drivers/ieee1394/raw1394.c3096
-rw-r--r--drivers/ieee1394/raw1394.h191
-rw-r--r--drivers/ieee1394/sbp2.c2138
-rw-r--r--drivers/ieee1394/sbp2.h346
-rw-r--r--drivers/ieee1394/video1394.c1528
-rw-r--r--drivers/ieee1394/video1394.h67
-rw-r--r--drivers/input/evdev.c100
-rw-r--r--drivers/input/gameport/emu10k1-gp.c44
-rw-r--r--drivers/input/gameport/fm801-gp.c10
-rw-r--r--drivers/input/input.c198
-rw-r--r--drivers/input/keyboard/Kconfig19
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/adp5588-keys.c2
-rw-r--r--drivers/input/keyboard/hil_kbd.c2
-rw-r--r--drivers/input/keyboard/nomadik-ske-keypad.c408
-rw-r--r--drivers/input/keyboard/omap4-keypad.c318
-rw-r--r--drivers/input/keyboard/twl4030_keypad.c7
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/ab8500-ponkey.c157
-rw-r--r--drivers/input/misc/ati_remote2.c93
-rw-r--r--drivers/input/misc/powermate.c2
-rw-r--r--drivers/input/mouse/elantech.c2
-rw-r--r--drivers/input/mouse/psmouse-base.c4
-rw-r--r--drivers/input/mouse/synaptics.c38
-rw-r--r--drivers/input/mouse/synaptics.h2
-rw-r--r--drivers/input/mouse/trackpoint.c2
-rw-r--r--drivers/input/mousedev.c2
-rw-r--r--drivers/input/serio/Kconfig9
-rw-r--r--drivers/input/serio/Makefile1
-rw-r--r--drivers/input/serio/i8042.c2
-rw-r--r--drivers/input/serio/ps2mult.c318
-rw-r--r--drivers/input/serio/serio.c125
-rw-r--r--drivers/input/sparse-keymap.c81
-rw-r--r--drivers/input/tablet/Kconfig11
-rw-r--r--drivers/input/tablet/Makefile1
-rw-r--r--drivers/input/tablet/hanwang.c446
-rw-r--r--drivers/input/tablet/wacom.h1
-rw-r--r--drivers/input/tablet/wacom_sys.c77
-rw-r--r--drivers/input/tablet/wacom_wac.c253
-rw-r--r--drivers/input/tablet/wacom_wac.h15
-rw-r--r--drivers/input/touchscreen/Kconfig34
-rw-r--r--drivers/input/touchscreen/Makefile3
-rw-r--r--drivers/input/touchscreen/ad7877.c144
-rw-r--r--drivers/input/touchscreen/ads7846.c886
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c648
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c4
-rw-r--r--drivers/input/touchscreen/hp680_ts_input.c6
-rw-r--r--drivers/input/touchscreen/intel-mid-touch.c687
-rw-r--r--drivers/input/touchscreen/lpc32xx_ts.c411
-rw-r--r--drivers/input/touchscreen/s3c2410_ts.c2
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c11
-rw-r--r--drivers/input/touchscreen/tps6507x-ts.c3
-rw-r--r--drivers/input/touchscreen/tsc2007.c2
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c185
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c18
-rw-r--r--drivers/media/IR/ir-keytable.c393
-rw-r--r--drivers/mfd/ab8500-core.c20
-rw-r--r--drivers/mfd/sh_mobile_sdhi.c2
-rw-r--r--drivers/mtd/devices/m25p80.c7
-rw-r--r--drivers/mtd/maps/physmap_of.c2
-rw-r--r--drivers/mtd/ofpart.c4
-rw-r--r--drivers/of/Kconfig5
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/address.c2
-rw-r--r--drivers/of/base.c4
-rw-r--r--drivers/of/device.c27
-rw-r--r--drivers/of/fdt.c2
-rw-r--r--drivers/of/irq.c39
-rw-r--r--drivers/of/of_i2c.c1
-rw-r--r--drivers/of/pdt.c276
-rw-r--r--drivers/of/platform.c34
-rw-r--r--drivers/platform/x86/Kconfig53
-rw-r--r--drivers/platform/x86/Makefile6
-rw-r--r--drivers/platform/x86/acer-wmi.c2
-rw-r--r--drivers/platform/x86/asus-laptop.c171
-rw-r--r--drivers/platform/x86/dell-laptop.c77
-rw-r--r--drivers/platform/x86/dell-wmi.c256
-rw-r--r--drivers/platform/x86/eeepc-laptop.c16
-rw-r--r--drivers/platform/x86/eeepc-wmi.c56
-rw-r--r--drivers/platform/x86/hdaps.c (renamed from drivers/hwmon/hdaps.c)2
-rw-r--r--drivers/platform/x86/hp-wmi.c172
-rw-r--r--drivers/platform/x86/ibm_rtl.c341
-rw-r--r--drivers/platform/x86/ideapad-laptop.c (renamed from drivers/platform/x86/ideapad_acpi.c)238
-rw-r--r--drivers/platform/x86/intel_pmic_gpio.c26
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c1
-rw-r--r--drivers/platform/x86/panasonic-laptop.c194
-rw-r--r--drivers/platform/x86/topstar-laptop.c161
-rw-r--r--drivers/platform/x86/toshiba_acpi.c191
-rw-r--r--drivers/platform/x86/wmi.c308
-rw-r--r--drivers/platform/x86/xo1-rfkill.c85
-rw-r--r--drivers/sbus/char/jsflash.c2
-rw-r--r--drivers/serial/68328serial.h5
-rw-r--r--drivers/serial/of_serial.c12
-rw-r--r--drivers/serial/sh-sci.h17
-rw-r--r--drivers/sh/Kconfig25
-rw-r--r--drivers/sh/Makefile7
-rw-r--r--drivers/sh/clk/Makefile3
-rw-r--r--drivers/sh/clk/core.c (renamed from drivers/sh/clk.c)203
-rw-r--r--drivers/sh/clk/cpg.c (renamed from drivers/sh/clk-cpg.c)11
-rw-r--r--drivers/sh/intc.c1390
-rw-r--r--drivers/sh/intc/Kconfig35
-rw-r--r--drivers/sh/intc/Makefile5
-rw-r--r--drivers/sh/intc/access.c237
-rw-r--r--drivers/sh/intc/balancing.c97
-rw-r--r--drivers/sh/intc/chip.c215
-rw-r--r--drivers/sh/intc/core.c469
-rw-r--r--drivers/sh/intc/dynamic.c135
-rw-r--r--drivers/sh/intc/handle.c307
-rw-r--r--drivers/sh/intc/internals.h186
-rw-r--r--drivers/sh/intc/userimask.c83
-rw-r--r--drivers/sh/intc/virq-debugfs.c64
-rw-r--r--drivers/sh/intc/virq.c255
-rw-r--r--drivers/sh/pfc.c17
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/mrst-touchscreen/Kconfig7
-rw-r--r--drivers/staging/mrst-touchscreen/Makefile3
-rw-r--r--drivers/staging/mrst-touchscreen/TODO2
-rw-r--r--drivers/staging/mrst-touchscreen/intel-mid-touch.c864
-rw-r--r--drivers/usb/host/r8a66597-hcd.c4
-rw-r--r--drivers/video/aty/atyfb_base.c3
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c6
-rw-r--r--fs/coda/cache.c17
-rw-r--r--fs/coda/cnode.c19
-rw-r--r--fs/coda/dir.c155
-rw-r--r--fs/coda/file.c31
-rw-r--r--fs/coda/inode.c61
-rw-r--r--fs/coda/pioctl.c22
-rw-r--r--fs/coda/psdev.c41
-rw-r--r--fs/coda/symlink.c3
-rw-r--r--fs/coda/upcall.c89
-rw-r--r--fs/partitions/check.c12
-rw-r--r--include/linux/blkdev.h1
-rw-r--r--include/linux/coda_fs_i.h13
-rw-r--r--include/linux/coda_linux.h6
-rw-r--r--include/linux/coda_psdev.h4
-rw-r--r--include/linux/elevator.h2
-rw-r--r--include/linux/gameport.h4
-rw-r--r--include/linux/genhd.h1
-rw-r--r--include/linux/input.h57
-rw-r--r--include/linux/input/bu21013.h44
-rw-r--r--include/linux/of_device.h13
-rw-r--r--include/linux/of_fdt.h2
-rw-r--r--include/linux/of_irq.h4
-rw-r--r--include/linux/of_pdt.h45
-rw-r--r--include/linux/pci_ids.h7
-rw-r--r--include/linux/serio.h10
-rw-r--r--include/linux/sh_clk.h17
-rw-r--r--include/linux/sh_intc.h16
-rw-r--r--include/linux/sh_pfc.h1
-rw-r--r--include/media/rc-map.h2
-rw-r--r--sound/soc/sh/siu_pcm.c2
446 files changed, 16247 insertions, 36188 deletions
diff --git a/Documentation/ABI/obsolete/dv1394 b/Documentation/ABI/obsolete/dv1394
deleted file mode 100644
index 2ee36864ca10..000000000000
--- a/Documentation/ABI/obsolete/dv1394
+++ /dev/null
@@ -1,9 +0,0 @@
-What: dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
-Contact: linux1394-devel@lists.sourceforge.net
-Description:
- New application development should use raw1394 + userspace libraries
- instead, notably libiec61883 which is functionally equivalent.
-
-Users:
- ffmpeg/libavformat (used by a variety of media players)
- dvgrab v1.x (replaced by dvgrab2 on top of raw1394 and resp. libraries)
diff --git a/Documentation/ABI/removed/dv1394 b/Documentation/ABI/removed/dv1394
new file mode 100644
index 000000000000..c2310b6676f4
--- /dev/null
+++ b/Documentation/ABI/removed/dv1394
@@ -0,0 +1,14 @@
+What: dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
+Date: May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact: linux1394-devel@lists.sourceforge.net
+Description:
+ /dev/dv1394/* were character device files, one for each FireWire
+ controller and for NTSC and PAL respectively, from which DV data
+ could be received by read() or transmitted by write(). A few
+ ioctl()s allowed limited control.
+ This special-purpose interface has been superseded by libraw1394 +
+ libiec61883 which are functionally equivalent, support HDV, and
+ transparently work on top of the newer firewire kernel drivers.
+
+Users:
+ ffmpeg/libavformat (if configured for DV1394)
diff --git a/Documentation/ABI/removed/raw1394 b/Documentation/ABI/removed/raw1394
new file mode 100644
index 000000000000..490aa1efc4ae
--- /dev/null
+++ b/Documentation/ABI/removed/raw1394
@@ -0,0 +1,15 @@
+What: raw1394 (a.k.a. "Raw IEEE1394 I/O support" for FireWire)
+Date: May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact: linux1394-devel@lists.sourceforge.net
+Description:
+ /dev/raw1394 was a character device file that allowed low-level
+ access to FireWire buses. Its major drawbacks were its inability
+ to implement sensible device security policies, and its low level
+ of abstraction that required userspace clients do duplicate much
+ of the kernel's ieee1394 core functionality.
+ Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
+ firewire-core.
+
+Users:
+ libraw1394 (works with firewire-cdev too, transparent to library ABI
+ users)
diff --git a/Documentation/ABI/removed/raw1394_legacy_isochronous b/Documentation/ABI/removed/raw1394_legacy_isochronous
deleted file mode 100644
index 1b629622d883..000000000000
--- a/Documentation/ABI/removed/raw1394_legacy_isochronous
+++ /dev/null
@@ -1,16 +0,0 @@
-What: legacy isochronous ABI of raw1394 (1st generation iso ABI)
-Date: June 2007 (scheduled), removed in kernel v2.6.23
-Contact: linux1394-devel@lists.sourceforge.net
-Description:
- The two request types RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN have
- been deprecated for quite some time. They are very inefficient as they
- come with high interrupt load and several layers of callbacks for each
- packet. Because of these deficiencies, the video1394 and dv1394 drivers
- and the 3rd-generation isochronous ABI in raw1394 (rawiso) were created.
-
-Users:
- libraw1394 users via the long deprecated API raw1394_iso_write,
- raw1394_start_iso_write, raw1394_start_iso_rcv, raw1394_stop_iso_rcv
-
- libdc1394, which optionally uses these old libraw1394 calls
- alternatively to the more efficient video1394 ABI
diff --git a/Documentation/ABI/removed/video1394 b/Documentation/ABI/removed/video1394
new file mode 100644
index 000000000000..c39c25aee77b
--- /dev/null
+++ b/Documentation/ABI/removed/video1394
@@ -0,0 +1,16 @@
+What: video1394 (a.k.a. "OHCI-1394 Video support" for FireWire)
+Date: May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact: linux1394-devel@lists.sourceforge.net
+Description:
+ /dev/video1394/* were character device files, one for each FireWire
+ controller, which were used for isochronous I/O. It was added as an
+ alternative to raw1394's isochronous I/O functionality which had
+ performance issues in its first generation. Any video1394 user had
+ to use raw1394 + libraw1394 too because video1394 did not provide
+ asynchronous I/O for device discovery and configuration.
+ Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
+ firewire-core.
+
+Users:
+ libdc1394 (works with firewire-cdev too, transparent to library ABI
+ users)
diff --git a/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
new file mode 100644
index 000000000000..b82deeaec314
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
@@ -0,0 +1,22 @@
+What: state
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The state file allows a means by which to change in and
+ out of Premium Real-Time Mode (PRTM), as well as the
+ ability to query the current state.
+ 0 => PRTM off
+ 1 => PRTM enabled
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
+What: version
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The version file provides a means by which to query
+ the RTL table version that lives in the Extended
+ BIOS Data Area (EBDA).
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 9961f1564d22..e833c8c81e69 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -502,16 +502,6 @@ Who: Thomas Gleixner <tglx@linutronix.de>
----------------------------
-What: old ieee1394 subsystem (CONFIG_IEEE1394)
-When: 2.6.37
-Files: drivers/ieee1394/ except init_ohci1394_dma.c
-Why: superseded by drivers/firewire/ (CONFIG_FIREWIRE) which offers more
- features, better performance, and better security, all with smaller
- and more modern code base
-Who: Stefan Richter <stefanr@s5r6.in-berlin.de>
-
-----------------------------
-
What: The acpi_sleep=s4_nonvs command line option
When: 2.6.37
Files: arch/x86/kernel/acpi/sleep.c
diff --git a/MAINTAINERS b/MAINTAINERS
index ebb9f9e8b583..8f72c90aec0f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2645,10 +2645,10 @@ F: drivers/net/greth*
HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
M: Frank Seidel <frank@f-seidel.de>
-L: lm-sensors@lm-sensors.org
+L: platform-driver-x86@vger.kernel.org
W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
S: Maintained
-F: drivers/hwmon/hdaps.c
+F: drivers/platform/x86/hdaps.c
HWPOISON MEMORY FAILURE HANDLING
M: Andi Kleen <andi@firstfloor.org>
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index fcb587f825cc..cac83a694880 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -18,12 +18,14 @@
#include <linux/amba/pl022.h>
#include <linux/spi/spi.h>
#include <linux/mfd/ab8500.h>
+#include <linux/input/matrix_keypad.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <plat/pincfg.h>
#include <plat/i2c.h>
+#include <plat/ske.h>
#include <mach/hardware.h>
#include <mach/setup.h>
@@ -49,6 +51,24 @@ static pin_cfg_t mop500_pins[] = {
GPIO11_I2C2_SCL,
GPIO229_I2C3_SDA,
GPIO230_I2C3_SCL,
+
+ /* SKE keypad */
+ GPIO153_KP_I7,
+ GPIO154_KP_I6,
+ GPIO155_KP_I5,
+ GPIO156_KP_I4,
+ GPIO157_KP_O7,
+ GPIO158_KP_O6,
+ GPIO159_KP_O5,
+ GPIO160_KP_O4,
+ GPIO161_KP_I3,
+ GPIO162_KP_I2,
+ GPIO163_KP_I1,
+ GPIO164_KP_I0,
+ GPIO165_KP_O3,
+ GPIO166_KP_O2,
+ GPIO167_KP_O1,
+ GPIO168_KP_O0,
};
static void ab4500_spi_cs_control(u32 command)
@@ -148,12 +168,120 @@ static struct amba_device *amba_devs[] __initdata = {
&u8500_ssp0_device,
};
+static const unsigned int ux500_keymap[] = {
+ KEY(2, 5, KEY_END),
+ KEY(4, 1, KEY_POWER),
+ KEY(3, 5, KEY_VOLUMEDOWN),
+ KEY(1, 3, KEY_3),
+ KEY(5, 2, KEY_RIGHT),
+ KEY(5, 0, KEY_9),
+
+ KEY(0, 5, KEY_MENU),
+ KEY(7, 6, KEY_ENTER),
+ KEY(4, 5, KEY_0),
+ KEY(6, 7, KEY_2),
+ KEY(3, 4, KEY_UP),
+ KEY(3, 3, KEY_DOWN),
+
+ KEY(6, 4, KEY_SEND),
+ KEY(6, 2, KEY_BACK),
+ KEY(4, 2, KEY_VOLUMEUP),
+ KEY(5, 5, KEY_1),
+ KEY(4, 3, KEY_LEFT),
+ KEY(3, 2, KEY_7),
+};
+
+static const struct matrix_keymap_data ux500_keymap_data = {
+ .keymap = ux500_keymap,
+ .keymap_size = ARRAY_SIZE(ux500_keymap),
+};
+
+/*
+ * Nomadik SKE keypad
+ */
+#define ROW_PIN_I0 164
+#define ROW_PIN_I1 163
+#define ROW_PIN_I2 162
+#define ROW_PIN_I3 161
+#define ROW_PIN_I4 156
+#define ROW_PIN_I5 155
+#define ROW_PIN_I6 154
+#define ROW_PIN_I7 153
+#define COL_PIN_O0 168
+#define COL_PIN_O1 167
+#define COL_PIN_O2 166
+#define COL_PIN_O3 165
+#define COL_PIN_O4 160
+#define COL_PIN_O5 159
+#define COL_PIN_O6 158
+#define COL_PIN_O7 157
+
+#define SKE_KPD_MAX_ROWS 8
+#define SKE_KPD_MAX_COLS 8
+
+static int ske_kp_rows[] = {
+ ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3,
+ ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7,
+};
+
+/*
+ * ske_set_gpio_row: request and set gpio rows
+ */
+static int ske_set_gpio_row(int gpio)
+{
+ int ret;
+
+ ret = gpio_request(gpio, "ske-kp");
+ if (ret < 0) {
+ pr_err("ske_set_gpio_row: gpio request failed\n");
+ return ret;
+ }
+
+ ret = gpio_direction_output(gpio, 1);
+ if (ret < 0) {
+ pr_err("ske_set_gpio_row: gpio direction failed\n");
+ gpio_free(gpio);
+ }
+
+ return ret;
+}
+
+/*
+ * ske_kp_init - enable the gpio configuration
+ */
+static int ske_kp_init(void)
+{
+ int ret, i;
+
+ for (i = 0; i < SKE_KPD_MAX_ROWS; i++) {
+ ret = ske_set_gpio_row(ske_kp_rows[i]);
+ if (ret < 0) {
+ pr_err("ske_kp_init: failed init\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static struct ske_keypad_platform_data ske_keypad_board = {
+ .init = ske_kp_init,
+ .keymap_data = &ux500_keymap_data,
+ .no_autorepeat = true,
+ .krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */
+ .kcol = SKE_KPD_MAX_COLS,
+ .debounce_ms = 40, /* in millsecs */
+};
+
+
+
/* add any platform devices here - TODO */
static struct platform_device *platform_devs[] __initdata = {
&u8500_i2c0_device,
&ux500_i2c1_device,
&ux500_i2c2_device,
&ux500_i2c3_device,
+ &ux500_ske_keypad_device,
};
static void __init u8500_init_machine(void)
@@ -168,6 +296,7 @@ static void __init u8500_init_machine(void)
ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data;
ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data;
ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data;
+ ux500_ske_keypad_device.dev.platform_data = &ske_keypad_board;
u8500_ssp0_device.dev.platform_data = &ssp0_platform_data;
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index d8ab7f184fe4..1675047daf20 100644
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -477,6 +477,7 @@ static struct clk_lookup u8500_common_clks[] = {
CLK(sdi5, "sdi5", NULL),
CLK(uart2, "uart2", NULL),
CLK(ske, "ske", NULL),
+ CLK(ske, "nmk-ske-keypad", NULL),
CLK(sdi2, "sdi2", NULL),
CLK(i2c0, "nmk-i2c.0", NULL),
CLK(fsmc, "fsmc", NULL),
diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c
index 40032fecbc16..cbbe69a76a7c 100644
--- a/arch/arm/mach-ux500/devices-db8500.c
+++ b/arch/arm/mach-ux500/devices-db8500.c
@@ -292,3 +292,23 @@ void dma40_u8500ed_fixup(void)
dma40_resources[1].start = U8500_DMA_LCPA_BASE_ED;
dma40_resources[1].end = U8500_DMA_LCPA_BASE_ED + 2 * SZ_1K - 1;
}
+
+struct resource keypad_resources[] = {
+ [0] = {
+ .start = U8500_SKE_BASE,
+ .end = U8500_SKE_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_DB8500_KB,
+ .end = IRQ_DB8500_KB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ux500_ske_keypad_device = {
+ .name = "nmk-ske-keypad",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(keypad_resources),
+ .resource = keypad_resources,
+};
diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h
index 33a120c2e82e..b91a4d1211a2 100644
--- a/arch/arm/mach-ux500/include/mach/devices.h
+++ b/arch/arm/mach-ux500/include/mach/devices.h
@@ -26,6 +26,7 @@ extern struct platform_device ux500_i2c3_device;
extern struct platform_device u8500_i2c0_device;
extern struct platform_device u8500_i2c4_device;
extern struct platform_device u8500_dma40_device;
+extern struct platform_device ux500_ske_keypad_device;
extern struct amba_device u8500_sdi0_device;
extern struct amba_device u8500_sdi1_device;
diff --git a/arch/arm/mach-ux500/pins-db8500.h b/arch/arm/mach-ux500/pins-db8500.h
index 66f8761cc823..f923764ee16c 100644
--- a/arch/arm/mach-ux500/pins-db8500.h
+++ b/arch/arm/mach-ux500/pins-db8500.h
@@ -459,82 +459,82 @@
#define GPIO152_KP_O9 PIN_CFG(152, ALT_C)
#define GPIO153_GPIO PIN_CFG(153, GPIO)
-#define GPIO153_KP_I7 PIN_CFG(153, ALT_A)
+#define GPIO153_KP_I7 PIN_CFG_PULL(153, ALT_A, DOWN)
#define GPIO153_LCD_D24 PIN_CFG(153, ALT_B)
#define GPIO153_U2_RXD PIN_CFG(153, ALT_C)
#define GPIO154_GPIO PIN_CFG(154, GPIO)
-#define GPIO154_KP_I6 PIN_CFG(154, ALT_A)
+#define GPIO154_KP_I6 PIN_CFG_PULL(154, ALT_A, DOWN)
#define GPIO154_LCD_D25 PIN_CFG(154, ALT_B)
#define GPIO154_U2_TXD PIN_CFG(154, ALT_C)
#define GPIO155_GPIO PIN_CFG(155, GPIO)
-#define GPIO155_KP_I5 PIN_CFG(155, ALT_A)
+#define GPIO155_KP_I5 PIN_CFG_PULL(155, ALT_A, DOWN)
#define GPIO155_LCD_D26 PIN_CFG(155, ALT_B)
#define GPIO155_STMAPE_CLK PIN_CFG(155, ALT_C)
#define GPIO156_GPIO PIN_CFG(156, GPIO)
-#define GPIO156_KP_I4 PIN_CFG(156, ALT_A)
+#define GPIO156_KP_I4 PIN_CFG_PULL(156, ALT_A, DOWN)
#define GPIO156_LCD_D27 PIN_CFG(156, ALT_B)
#define GPIO156_STMAPE_DAT3 PIN_CFG(156, ALT_C)
#define GPIO157_GPIO PIN_CFG(157, GPIO)
-#define GPIO157_KP_O7 PIN_CFG(157, ALT_A)
+#define GPIO157_KP_O7 PIN_CFG_PULL(157, ALT_A, UP)
#define GPIO157_LCD_D28 PIN_CFG(157, ALT_B)
#define GPIO157_STMAPE_DAT2 PIN_CFG(157, ALT_C)
#define GPIO158_GPIO PIN_CFG(158, GPIO)
-#define GPIO158_KP_O6 PIN_CFG(158, ALT_A)
+#define GPIO158_KP_O6 PIN_CFG_PULL(158, ALT_A, UP)
#define GPIO158_LCD_D29 PIN_CFG(158, ALT_B)
#define GPIO158_STMAPE_DAT1 PIN_CFG(158, ALT_C)
#define GPIO159_GPIO PIN_CFG(159, GPIO)
-#define GPIO159_KP_O5 PIN_CFG(159, ALT_A)
+#define GPIO159_KP_O5 PIN_CFG_PULL(159, ALT_A, UP)
#define GPIO159_LCD_D30 PIN_CFG(159, ALT_B)
#define GPIO159_STMAPE_DAT0 PIN_CFG(159, ALT_C)
#define GPIO160_GPIO PIN_CFG(160, GPIO)
-#define GPIO160_KP_O4 PIN_CFG(160, ALT_A)
+#define GPIO160_KP_O4 PIN_CFG_PULL(160, ALT_A, UP)
#define GPIO160_LCD_D31 PIN_CFG(160, ALT_B)
#define GPIO160_NONE PIN_CFG(160, ALT_C)
#define GPIO161_GPIO PIN_CFG(161, GPIO)
-#define GPIO161_KP_I3 PIN_CFG(161, ALT_A)
+#define GPIO161_KP_I3 PIN_CFG_PULL(161, ALT_A, DOWN)
#define GPIO161_LCD_D32 PIN_CFG(161, ALT_B)
#define GPIO161_UARTMOD_RXD PIN_CFG(161, ALT_C)
#define GPIO162_GPIO PIN_CFG(162, GPIO)
-#define GPIO162_KP_I2 PIN_CFG(162, ALT_A)
+#define GPIO162_KP_I2 PIN_CFG_PULL(162, ALT_A, DOWN)
#define GPIO162_LCD_D33 PIN_CFG(162, ALT_B)
#define GPIO162_UARTMOD_TXD PIN_CFG(162, ALT_C)
#define GPIO163_GPIO PIN_CFG(163, GPIO)
-#define GPIO163_KP_I1 PIN_CFG(163, ALT_A)
+#define GPIO163_KP_I1 PIN_CFG_PULL(163, ALT_A, DOWN)
#define GPIO163_LCD_D34 PIN_CFG(163, ALT_B)
#define GPIO163_STMMOD_CLK PIN_CFG(163, ALT_C)
#define GPIO164_GPIO PIN_CFG(164, GPIO)
-#define GPIO164_KP_I0 PIN_CFG(164, ALT_A)
+#define GPIO164_KP_I0 PIN_CFG_PULL(164, ALT_A, UP)
#define GPIO164_LCD_D35 PIN_CFG(164, ALT_B)
#define GPIO164_STMMOD_DAT3 PIN_CFG(164, ALT_C)
#define GPIO165_GPIO PIN_CFG(165, GPIO)
-#define GPIO165_KP_O3 PIN_CFG(165, ALT_A)
+#define GPIO165_KP_O3 PIN_CFG_PULL(165, ALT_A, UP)
#define GPIO165_LCD_D36 PIN_CFG(165, ALT_B)
#define GPIO165_STMMOD_DAT2 PIN_CFG(165, ALT_C)
#define GPIO166_GPIO PIN_CFG(166, GPIO)
-#define GPIO166_KP_O2 PIN_CFG(166, ALT_A)
+#define GPIO166_KP_O2 PIN_CFG_PULL(166, ALT_A, UP)
#define GPIO166_LCD_D37 PIN_CFG(166, ALT_B)
#define GPIO166_STMMOD_DAT1 PIN_CFG(166, ALT_C)
#define GPIO167_GPIO PIN_CFG(167, GPIO)
-#define GPIO167_KP_O1 PIN_CFG(167, ALT_A)
+#define GPIO167_KP_O1 PIN_CFG_PULL(167, ALT_A, UP)
#define GPIO167_LCD_D38 PIN_CFG(167, ALT_B)
#define GPIO167_STMMOD_DAT0 PIN_CFG(167, ALT_C)
#define GPIO168_GPIO PIN_CFG(168, GPIO)
-#define GPIO168_KP_O0 PIN_CFG(168, ALT_A)
+#define GPIO168_KP_O0 PIN_CFG_PULL(168, ALT_A, UP)
#define GPIO168_LCD_D39 PIN_CFG(168, ALT_B)
#define GPIO168_NONE PIN_CFG(168, ALT_C)
diff --git a/arch/arm/plat-nomadik/include/plat/ske.h b/arch/arm/plat-nomadik/include/plat/ske.h
new file mode 100644
index 000000000000..31382fbc07dc
--- /dev/null
+++ b/arch/arm/plat-nomadik/include/plat/ske.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
+ *
+ * ux500 Scroll key and Keypad Encoder (SKE) header
+ */
+
+#ifndef __SKE_H
+#define __SKE_H
+
+#include <linux/input/matrix_keypad.h>
+
+/* register definitions for SKE peripheral */
+#define SKE_CR 0x00
+#define SKE_VAL0 0x04
+#define SKE_VAL1 0x08
+#define SKE_DBCR 0x0C
+#define SKE_IMSC 0x10
+#define SKE_RIS 0x14
+#define SKE_MIS 0x18
+#define SKE_ICR 0x1C
+
+/*
+ * Keypad module
+ */
+
+/**
+ * struct keypad_platform_data - structure for platform specific data
+ * @init: pointer to keypad init function
+ * @exit: pointer to keypad deinitialisation function
+ * @keymap_data: matrix scan code table for keycodes
+ * @krow: maximum number of rows
+ * @kcol: maximum number of columns
+ * @debounce_ms: platform specific debounce time
+ * @no_autorepeat: flag for auto repetition
+ * @wakeup_enable: allow waking up the system
+ */
+struct ske_keypad_platform_data {
+ int (*init)(void);
+ int (*exit)(void);
+ const struct matrix_keymap_data *keymap_data;
+ u8 krow;
+ u8 kcol;
+ u8 debounce_ms;
+ bool no_autorepeat;
+ bool wakeup_enable;
+};
+#endif /*__SKE_KPD_H*/
diff --git a/arch/arm/plat-omap/include/plat/omap4-keypad.h b/arch/arm/plat-omap/include/plat/omap4-keypad.h
new file mode 100644
index 000000000000..2b1d9bc1eebb
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/omap4-keypad.h
@@ -0,0 +1,14 @@
+#ifndef ARCH_ARM_PLAT_OMAP4_KEYPAD_H
+#define ARCH_ARM_PLAT_OMAP4_KEYPAD_H
+
+#include <linux/input/matrix_keypad.h>
+
+struct omap4_keypad_platform_data {
+ const struct matrix_keymap_data *keymap_data;
+
+ u8 rows;
+ u8 cols;
+};
+
+extern int omap4_keyboard_init(struct omap4_keypad_platform_data *);
+#endif
diff --git a/arch/m68k/include/asm/cacheflush_no.h b/arch/m68k/include/asm/cacheflush_no.h
index 89f195656be7..7085bd51668b 100644
--- a/arch/m68k/include/asm/cacheflush_no.h
+++ b/arch/m68k/include/asm/cacheflush_no.h
@@ -29,7 +29,7 @@
static inline void __flush_cache_all(void)
{
-#ifdef CONFIG_M5407
+#if defined(CONFIG_M5407) || defined(CONFIG_M548x)
/*
* Use cpushl to push and invalidate all cache lines.
* Gas doesn't seem to know how to generate the ColdFire
diff --git a/arch/m68k/include/asm/coldfire.h b/arch/m68k/include/asm/coldfire.h
index 83a9fa4e618a..3b0a34d0fe33 100644
--- a/arch/m68k/include/asm/coldfire.h
+++ b/arch/m68k/include/asm/coldfire.h
@@ -32,7 +32,9 @@
*/
#define MCF_MBAR 0x10000000
#define MCF_MBAR2 0x80000000
-#if defined(CONFIG_M520x)
+#if defined(CONFIG_M548x)
+#define MCF_IPSBAR MCF_MBAR
+#elif defined(CONFIG_M520x)
#define MCF_IPSBAR 0xFC000000
#else
#define MCF_IPSBAR 0x40000000
diff --git a/arch/m68k/include/asm/gpio.h b/arch/m68k/include/asm/gpio.h
index 283214dc65a7..1b57adbafad5 100644
--- a/arch/m68k/include/asm/gpio.h
+++ b/arch/m68k/include/asm/gpio.h
@@ -36,7 +36,8 @@
*/
#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
- defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+ defined(CONFIG_M532x) || defined(CONFIG_M548x)
/* These parts have GPIO organized by 8 bit ports */
@@ -136,6 +137,8 @@ static inline u32 __mcf_gpio_ppdr(unsigned gpio)
#endif
else
return MCFGPIO_PPDR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+ return 0;
#endif
}
@@ -173,6 +176,8 @@ static inline u32 __mcf_gpio_podr(unsigned gpio)
#endif
else
return MCFGPIO_PODR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+ return 0;
#endif
}
diff --git a/arch/m68k/include/asm/m548xgpt.h b/arch/m68k/include/asm/m548xgpt.h
new file mode 100644
index 000000000000..c8ef158a1c4e
--- /dev/null
+++ b/arch/m68k/include/asm/m548xgpt.h
@@ -0,0 +1,88 @@
+/*
+ * File: m548xgpt.h
+ * Purpose: Register and bit definitions for the MCF548X
+ *
+ * Notes:
+ *
+ */
+
+#ifndef m548xgpt_h
+#define m548xgpt_h
+
+/*********************************************************************
+*
+* General Purpose Timers (GPT)
+*
+*********************************************************************/
+
+/* Register read/write macros */
+#define MCF_GPT_GMS0 0x000800
+#define MCF_GPT_GCIR0 0x000804
+#define MCF_GPT_GPWM0 0x000808
+#define MCF_GPT_GSR0 0x00080C
+#define MCF_GPT_GMS1 0x000810
+#define MCF_GPT_GCIR1 0x000814
+#define MCF_GPT_GPWM1 0x000818
+#define MCF_GPT_GSR1 0x00081C
+#define MCF_GPT_GMS2 0x000820
+#define MCF_GPT_GCIR2 0x000824
+#define MCF_GPT_GPWM2 0x000828
+#define MCF_GPT_GSR2 0x00082C
+#define MCF_GPT_GMS3 0x000830
+#define MCF_GPT_GCIR3 0x000834
+#define MCF_GPT_GPWM3 0x000838
+#define MCF_GPT_GSR3 0x00083C
+#define MCF_GPT_GMS(x) (0x000800+((x)*0x010))
+#define MCF_GPT_GCIR(x) (0x000804+((x)*0x010))
+#define MCF_GPT_GPWM(x) (0x000808+((x)*0x010))
+#define MCF_GPT_GSR(x) (0x00080C+((x)*0x010))
+
+/* Bit definitions and macros for MCF_GPT_GMS */
+#define MCF_GPT_GMS_TMS(x) (((x)&0x00000007)<<0)
+#define MCF_GPT_GMS_GPIO(x) (((x)&0x00000003)<<4)
+#define MCF_GPT_GMS_IEN (0x00000100)
+#define MCF_GPT_GMS_OD (0x00000200)
+#define MCF_GPT_GMS_SC (0x00000400)
+#define MCF_GPT_GMS_CE (0x00001000)
+#define MCF_GPT_GMS_WDEN (0x00008000)
+#define MCF_GPT_GMS_ICT(x) (((x)&0x00000003)<<16)
+#define MCF_GPT_GMS_OCT(x) (((x)&0x00000003)<<20)
+#define MCF_GPT_GMS_OCPW(x) (((x)&0x000000FF)<<24)
+#define MCF_GPT_GMS_OCT_FRCLOW (0x00000000)
+#define MCF_GPT_GMS_OCT_PULSEHI (0x00100000)
+#define MCF_GPT_GMS_OCT_PULSELO (0x00200000)
+#define MCF_GPT_GMS_OCT_TOGGLE (0x00300000)
+#define MCF_GPT_GMS_ICT_ANY (0x00000000)
+#define MCF_GPT_GMS_ICT_RISE (0x00010000)
+#define MCF_GPT_GMS_ICT_FALL (0x00020000)
+#define MCF_GPT_GMS_ICT_PULSE (0x00030000)
+#define MCF_GPT_GMS_GPIO_INPUT (0x00000000)
+#define MCF_GPT_GMS_GPIO_OUTLO (0x00000020)
+#define MCF_GPT_GMS_GPIO_OUTHI (0x00000030)
+#define MCF_GPT_GMS_TMS_DISABLE (0x00000000)
+#define MCF_GPT_GMS_TMS_INCAPT (0x00000001)
+#define MCF_GPT_GMS_TMS_OUTCAPT (0x00000002)
+#define MCF_GPT_GMS_TMS_PWM (0x00000003)
+#define MCF_GPT_GMS_TMS_GPIO (0x00000004)
+
+/* Bit definitions and macros for MCF_GPT_GCIR */
+#define MCF_GPT_GCIR_CNT(x) (((x)&0x0000FFFF)<<0)
+#define MCF_GPT_GCIR_PRE(x) (((x)&0x0000FFFF)<<16)
+
+/* Bit definitions and macros for MCF_GPT_GPWM */
+#define MCF_GPT_GPWM_LOAD (0x00000001)
+#define MCF_GPT_GPWM_PWMOP (0x00000100)
+#define MCF_GPT_GPWM_WIDTH(x) (((x)&0x0000FFFF)<<16)
+
+/* Bit definitions and macros for MCF_GPT_GSR */
+#define MCF_GPT_GSR_CAPT (0x00000001)
+#define MCF_GPT_GSR_COMP (0x00000002)
+#define MCF_GPT_GSR_PWMP (0x00000004)
+#define MCF_GPT_GSR_TEXP (0x00000008)
+#define MCF_GPT_GSR_PIN (0x00000100)
+#define MCF_GPT_GSR_OVF(x) (((x)&0x00000007)<<12)
+#define MCF_GPT_GSR_CAPTURE(x) (((x)&0x0000FFFF)<<16)
+
+/********************************************************************/
+
+#endif /* m548xgpt_h */
diff --git a/arch/m68k/include/asm/m548xsim.h b/arch/m68k/include/asm/m548xsim.h
new file mode 100644
index 000000000000..149135ef30d2
--- /dev/null
+++ b/arch/m68k/include/asm/m548xsim.h
@@ -0,0 +1,55 @@
+/*
+ * m548xsim.h -- ColdFire 547x/548x System Integration Unit support.
+ */
+
+#ifndef m548xsim_h
+#define m548xsim_h
+
+#define MCFINT_VECBASE 64
+
+/*
+ * Interrupt Controller Registers
+ */
+#define MCFICM_INTC0 0x0700 /* Base for Interrupt Ctrl 0 */
+#define MCFINTC_IPRH 0x00 /* Interrupt pending 32-63 */
+#define MCFINTC_IPRL 0x04 /* Interrupt pending 1-31 */
+#define MCFINTC_IMRH 0x08 /* Interrupt mask 32-63 */
+#define MCFINTC_IMRL 0x0c /* Interrupt mask 1-31 */
+#define MCFINTC_INTFRCH 0x10 /* Interrupt force 32-63 */
+#define MCFINTC_INTFRCL 0x14 /* Interrupt force 1-31 */
+#define MCFINTC_IRLR 0x18 /* */
+#define MCFINTC_IACKL 0x19 /* */
+#define MCFINTC_ICR0 0x40 /* Base ICR register */
+
+/*
+ * Define system peripheral IRQ usage.
+ */
+#define MCF_IRQ_TIMER (64 + 54) /* Slice Timer 0 */
+#define MCF_IRQ_PROFILER (64 + 53) /* Slice Timer 1 */
+
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PIN_MAX 0 /* I am too lazy to count */
+#define MCFGPIO_IRQ_MAX -1
+#define MCFGPIO_IRQ_VECBASE -1
+
+/*
+ * Some PSC related definitions
+ */
+#define MCF_PAR_PSC(x) (0x000A4F-((x)&0x3))
+#define MCF_PAR_SDA (0x0008)
+#define MCF_PAR_SCL (0x0004)
+#define MCF_PAR_PSC_TXD (0x04)
+#define MCF_PAR_PSC_RXD (0x08)
+#define MCF_PAR_PSC_RTS(x) (((x)&0x03)<<4)
+#define MCF_PAR_PSC_CTS(x) (((x)&0x03)<<6)
+#define MCF_PAR_PSC_CTS_GPIO (0x00)
+#define MCF_PAR_PSC_CTS_BCLK (0x80)
+#define MCF_PAR_PSC_CTS_CTS (0xC0)
+#define MCF_PAR_PSC_RTS_GPIO (0x00)
+#define MCF_PAR_PSC_RTS_FSYNC (0x20)
+#define MCF_PAR_PSC_RTS_RTS (0x30)
+#define MCF_PAR_PSC_CANRX (0x40)
+
+#endif /* m548xsim_h */
diff --git a/arch/m68k/include/asm/mcfcache.h b/arch/m68k/include/asm/mcfcache.h
index c042634fadaa..f49dfc09f70a 100644
--- a/arch/m68k/include/asm/mcfcache.h
+++ b/arch/m68k/include/asm/mcfcache.h
@@ -107,7 +107,7 @@
.endm
#endif /* CONFIG_M532x */
-#if defined(CONFIG_M5407)
+#if defined(CONFIG_M5407) || defined(CONFIG_M548x)
/*
* Version 4 cores have a true harvard style separate instruction
* and data cache. Invalidate and enable cache, also enable write
diff --git a/arch/m68k/include/asm/mcfsim.h b/arch/m68k/include/asm/mcfsim.h
index 9c70a67bf85f..6901fd68165b 100644
--- a/arch/m68k/include/asm/mcfsim.h
+++ b/arch/m68k/include/asm/mcfsim.h
@@ -41,6 +41,8 @@
#elif defined(CONFIG_M5407)
#include <asm/m5407sim.h>
#include <asm/mcfintc.h>
+#elif defined(CONFIG_M548x)
+#include <asm/m548xsim.h>
#endif
/****************************************************************************/
diff --git a/arch/m68k/include/asm/mcfslt.h b/arch/m68k/include/asm/mcfslt.h
new file mode 100644
index 000000000000..d0d0ecba5333
--- /dev/null
+++ b/arch/m68k/include/asm/mcfslt.h
@@ -0,0 +1,44 @@
+/****************************************************************************/
+
+/*
+ * mcfslt.h -- ColdFire internal Slice (SLT) timer support defines.
+ *
+ * (C) Copyright 2004, Greg Ungerer (gerg@snapgear.com)
+ * (C) Copyright 2009, Philippe De Muyter (phdm@macqel.be)
+ */
+
+/****************************************************************************/
+#ifndef mcfslt_h
+#define mcfslt_h
+/****************************************************************************/
+
+/*
+ * Get address specific defines for the 547x.
+ */
+#define MCFSLT_TIMER0 0x900 /* Base address of TIMER0 */
+#define MCFSLT_TIMER1 0x910 /* Base address of TIMER1 */
+
+
+/*
+ * Define the SLT timer register set addresses.
+ */
+#define MCFSLT_STCNT 0x00 /* Terminal count */
+#define MCFSLT_SCR 0x04 /* Control */
+#define MCFSLT_SCNT 0x08 /* Current count */
+#define MCFSLT_SSR 0x0C /* Status */
+
+/*
+ * Bit definitions for the SCR control register.
+ */
+#define MCFSLT_SCR_RUN 0x04000000 /* Run mode (continuous) */
+#define MCFSLT_SCR_IEN 0x02000000 /* Interrupt enable */
+#define MCFSLT_SCR_TEN 0x01000000 /* Timer enable */
+
+/*
+ * Bit definitions for the SSR status register.
+ */
+#define MCFSLT_SSR_BE 0x02000000 /* Bus error condition */
+#define MCFSLT_SSR_TE 0x01000000 /* Timeout condition */
+
+/****************************************************************************/
+#endif /* mcfslt_h */
diff --git a/arch/m68k/include/asm/mcfuart.h b/arch/m68k/include/asm/mcfuart.h
index 01a8716c5fc5..db72e2b889ca 100644
--- a/arch/m68k/include/asm/mcfuart.h
+++ b/arch/m68k/include/asm/mcfuart.h
@@ -47,6 +47,11 @@
#define MCFUART_BASE1 0xfc060000 /* Base address of UART1 */
#define MCFUART_BASE2 0xfc064000 /* Base address of UART2 */
#define MCFUART_BASE3 0xfc068000 /* Base address of UART3 */
+#elif defined(CONFIG_M548x)
+#define MCFUART_BASE1 0x8600 /* on M548x */
+#define MCFUART_BASE2 0x8700 /* on M548x */
+#define MCFUART_BASE3 0x8800 /* on M548x */
+#define MCFUART_BASE4 0x8900 /* on M548x */
#endif
@@ -212,7 +217,9 @@ struct mcf_platform_uart {
#define MCFUART_URF_RXS 0xc0 /* Receiver status */
#endif
-#if defined(CONFIG_M5272)
+#if defined(CONFIG_M548x)
+#define MCFUART_TXFIFOSIZE 512
+#elif defined(CONFIG_M5272)
#define MCFUART_TXFIFOSIZE 25
#else
#define MCFUART_TXFIFOSIZE 1
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c
index 73e5e581245b..78e59b82ebc3 100644
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -22,13 +22,9 @@
int main(void)
{
/* offsets into the task struct */
- DEFINE(TASK_STATE, offsetof(struct task_struct, state));
- DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
- DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
- DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
#ifdef CONFIG_MMU
DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
#endif
@@ -64,14 +60,6 @@ int main(void)
/* bitfields are a bit difficult */
DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
- /* offsets into the irq_handler struct */
- DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
- DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
- DEFINE(IRQ_NEXT, offsetof(struct irq_node, next));
-
- /* offsets into the kernel_stat struct */
- DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
-
/* offsets into the irq_cpustat_t struct */
DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index 2609c394e1df..9287150e5fb0 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -59,6 +59,10 @@ config GENERIC_HARDIRQS
bool
default y
+config GENERIC_HARDIRQS_NO__DO_IRQ
+ bool
+ default y
+
config GENERIC_CALIBRATE_DELAY
bool
default y
@@ -171,6 +175,11 @@ config M5407
help
Motorola ColdFire 5407 processor support.
+config M548x
+ bool "MCF548x"
+ help
+ Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support.
+
endchoice
config M527x
@@ -181,7 +190,7 @@ config M527x
config COLDFIRE
bool
- depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407)
+ depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M548x)
select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB
default y
diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile
index 14042574ac21..026ef16fa68e 100644
--- a/arch/m68knommu/Makefile
+++ b/arch/m68knommu/Makefile
@@ -25,6 +25,7 @@ platform-$(CONFIG_M528x) := 528x
platform-$(CONFIG_M5307) := 5307
platform-$(CONFIG_M532x) := 532x
platform-$(CONFIG_M5407) := 5407
+platform-$(CONFIG_M548x) := 548x
PLATFORM := $(platform-y)
board-$(CONFIG_PILOT) := pilot
@@ -73,6 +74,7 @@ cpuclass-$(CONFIG_M528x) := coldfire
cpuclass-$(CONFIG_M5307) := coldfire
cpuclass-$(CONFIG_M532x) := coldfire
cpuclass-$(CONFIG_M5407) := coldfire
+cpuclass-$(CONFIG_M548x) := coldfire
cpuclass-$(CONFIG_M68328) := 68328
cpuclass-$(CONFIG_M68EZ328) := 68328
cpuclass-$(CONFIG_M68VZ328) := 68328
@@ -100,6 +102,7 @@ cflags-$(CONFIG_M528x) := $(call cc-option,-m528x,-m5307)
cflags-$(CONFIG_M5307) := $(call cc-option,-m5307,-m5200)
cflags-$(CONFIG_M532x) := $(call cc-option,-mcpu=532x,-m5307)
cflags-$(CONFIG_M5407) := $(call cc-option,-m5407,-m5200)
+cflags-$(CONFIG_M548x) := $(call cc-option,-m5407,-m5200)
cflags-$(CONFIG_M68328) := -m68000
cflags-$(CONFIG_M68EZ328) := -m68000
cflags-$(CONFIG_M68VZ328) := -m68000
diff --git a/arch/m68knommu/kernel/.gitignore b/arch/m68knommu/kernel/.gitignore
new file mode 100644
index 000000000000..c5f676c3c224
--- /dev/null
+++ b/arch/m68knommu/kernel/.gitignore
@@ -0,0 +1 @@
+vmlinux.lds
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c
index 24335022fa2c..ffe02f41ad46 100644
--- a/arch/m68knommu/kernel/asm-offsets.c
+++ b/arch/m68knommu/kernel/asm-offsets.c
@@ -21,14 +21,8 @@
int main(void)
{
/* offsets into the task struct */
- DEFINE(TASK_STATE, offsetof(struct task_struct, state));
- DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
- DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
- DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
- DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
- DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
/* offsets into the irq_cpustat_t struct */
DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
@@ -63,7 +57,7 @@ int main(void)
DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
#else
/* bitfields are a bit difficult */
- DEFINE(PT_OFF_VECTOR, offsetof(struct pt_regs, pc) + 4);
+ DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
#endif
/* signal defines */
@@ -75,11 +69,8 @@ int main(void)
DEFINE(PT_PTRACED, PT_PTRACED);
/* Offsets in thread_info structure */
- 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));
DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
- DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
return 0;
}
diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c
index f6be1248d216..6fe7c38cd556 100644
--- a/arch/m68knommu/kernel/ptrace.c
+++ b/arch/m68knommu/kernel/ptrace.c
@@ -18,6 +18,7 @@
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/signal.h>
+#include <linux/tracehook.h>
#include <asm/uaccess.h>
#include <asm/page.h>
@@ -134,14 +135,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
tmp >>= 16;
} else if (addr >= 21 && addr < 49) {
tmp = child->thread.fp[addr - 21];
-#ifdef CONFIG_M68KFPU_EMU
- /* Convert internal fpu reg representation
- * into long double format
- */
- if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
- tmp = ((tmp & 0xffff0000) << 15) |
- ((tmp & 0x0000ffff) << 16);
-#endif
} else if (addr == 49) {
tmp = child->mm->start_code;
} else if (addr == 50) {
@@ -175,16 +168,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
if (addr >= 21 && addr < 48)
{
-#ifdef CONFIG_M68KFPU_EMU
- /* Convert long double format
- * into internal fpu reg representation
- */
- if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
- data = (unsigned long)data << 15;
- data = (data & 0xffff0000) |
- ((data & 0x0000ffff) >> 1);
- }
-#endif
child->thread.fp[addr - 21] = data;
ret = 0;
}
@@ -259,21 +242,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return ret;
}
-asmlinkage void syscall_trace(void)
+asmlinkage int syscall_trace_enter(void)
{
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
- if (!(current->ptrace & PT_PTRACED))
- return;
- ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
- ? 0x80 : 0));
- /*
- * this isn't the same as continuing with a signal, but it will do
- * for normal use. strace only continues with a signal if the
- * stopping signal is not SIGTRAP. -brl
- */
- if (current->exit_code) {
- send_sig(current->exit_code, current, 1);
- current->exit_code = 0;
- }
+ int ret = 0;
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ ret = tracehook_report_syscall_entry(task_pt_regs(current));
+ return ret;
+}
+
+asmlinkage void syscall_trace_leave(void)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(task_pt_regs(current), 0);
}
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index ba92b90d5fbc..c684adf5dc40 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -54,9 +54,6 @@ void (*mach_reset)(void);
void (*mach_halt)(void);
void (*mach_power_off)(void);
-#ifdef CONFIG_M68000
- #define CPU "MC68000"
-#endif
#ifdef CONFIG_M68328
#define CPU "MC68328"
#endif
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
index 7089dd9d843b..d6ac2a43453c 100644
--- a/arch/m68knommu/kernel/time.c
+++ b/arch/m68knommu/kernel/time.c
@@ -60,13 +60,16 @@ static unsigned long read_rtc_mmss(void)
{
unsigned int year, mon, day, hour, min, sec;
- if (mach_gettod)
+ if (mach_gettod) {
mach_gettod(&year, &mon, &day, &hour, &min, &sec);
- else
- year = mon = day = hour = min = sec = 0;
+ if ((year += 1900) < 1970)
+ year += 100;
+ } else {
+ year = 1970;
+ mon = day = 1;
+ hour = min = sec = 0;
+ }
- if ((year += 1900) < 1970)
- year += 100;
return mktime(year, mon, day, hour, min, sec);
}
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
index 3739c8f657d7..a768008dfd06 100644
--- a/arch/m68knommu/kernel/traps.c
+++ b/arch/m68knommu/kernel/traps.c
@@ -179,14 +179,16 @@ static void __show_stack(struct task_struct *task, unsigned long *stack)
void bad_super_trap(struct frame *fp)
{
+ int vector = (fp->ptregs.vector >> 2) & 0xff;
+
console_verbose();
- if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
+ if (vector < ARRAY_SIZE(vec_names))
printk (KERN_WARNING "*** %s *** FORMAT=%X\n",
- vec_names[(fp->ptregs.vector) >> 2],
+ vec_names[vector],
fp->ptregs.format);
else
printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n",
- (fp->ptregs.vector) >> 2,
+ vector,
fp->ptregs.format);
printk (KERN_WARNING "Current process id is %d\n", current->pid);
die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
@@ -195,10 +197,11 @@ void bad_super_trap(struct frame *fp)
asmlinkage void trap_c(struct frame *fp)
{
int sig;
+ int vector = (fp->ptregs.vector >> 2) & 0xff;
siginfo_t info;
if (fp->ptregs.sr & PS_S) {
- if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
+ if (vector == VEC_TRACE) {
/* traced a trapping instruction */
} else
bad_super_trap(fp);
@@ -206,7 +209,7 @@ asmlinkage void trap_c(struct frame *fp)
}
/* send the appropriate signal to the user program */
- switch ((fp->ptregs.vector) >> 2) {
+ switch (vector) {
case VEC_ADDRERR:
info.si_code = BUS_ADRALN;
sig = SIGBUS;
@@ -360,16 +363,3 @@ void show_stack(struct task_struct *task, unsigned long *stack)
else
__show_stack(task, stack);
}
-
-#ifdef CONFIG_M68KFPU_EMU
-asmlinkage void fpemu_signal(int signal, int code, void *addr)
-{
- siginfo_t info;
-
- info.si_signo = signal;
- info.si_errno = 0;
- info.si_code = code;
- info.si_addr = addr;
- force_sig_info(signal, &info, current);
-}
-#endif
diff --git a/arch/m68knommu/platform/5206/Makefile b/arch/m68knommu/platform/5206/Makefile
index 113c33390064..b5db05625cfa 100644
--- a/arch/m68knommu/platform/5206/Makefile
+++ b/arch/m68knommu/platform/5206/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5206e/Makefile b/arch/m68knommu/platform/5206e/Makefile
index 113c33390064..b5db05625cfa 100644
--- a/arch/m68knommu/platform/5206e/Makefile
+++ b/arch/m68knommu/platform/5206e/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/520x/Makefile b/arch/m68knommu/platform/520x/Makefile
index 435ab3483dc1..ad3f4e5a57ce 100644
--- a/arch/m68knommu/platform/520x/Makefile
+++ b/arch/m68knommu/platform/520x/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/523x/Makefile b/arch/m68knommu/platform/523x/Makefile
index b8f9b45440c2..c04b8f71c88c 100644
--- a/arch/m68knommu/platform/523x/Makefile
+++ b/arch/m68knommu/platform/523x/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5249/Makefile b/arch/m68knommu/platform/5249/Makefile
index f56225d1582f..4bed30fd0073 100644
--- a/arch/m68knommu/platform/5249/Makefile
+++ b/arch/m68knommu/platform/5249/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5272/Makefile b/arch/m68knommu/platform/5272/Makefile
index 93673ef8e2c1..34110fc14301 100644
--- a/arch/m68knommu/platform/5272/Makefile
+++ b/arch/m68knommu/platform/5272/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c
index 59278c0887d0..65bb582734e1 100644
--- a/arch/m68knommu/platform/5272/config.c
+++ b/arch/m68knommu/platform/5272/config.c
@@ -13,6 +13,8 @@
#include <linux/param.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
#include <asm/machdep.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
@@ -148,9 +150,23 @@ void __init config_BSP(char *commandp, int size)
/***************************************************************************/
+/*
+ * Some 5272 based boards have the FEC ethernet diectly connected to
+ * an ethernet switch. In this case we need to use the fixed phy type,
+ * and we need to declare it early in boot.
+ */
+static struct fixed_phy_status nettel_fixed_phy_status __initdata = {
+ .link = 1,
+ .speed = 100,
+ .duplex = 0,
+};
+
+/***************************************************************************/
+
static int __init init_BSP(void)
{
m5272_uarts_init();
+ fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status);
platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
return 0;
}
diff --git a/arch/m68knommu/platform/5272/intc.c b/arch/m68knommu/platform/5272/intc.c
index 7081e0a9720e..3cf681c177aa 100644
--- a/arch/m68knommu/platform/5272/intc.c
+++ b/arch/m68knommu/platform/5272/intc.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <asm/coldfire.h>
@@ -29,6 +30,10 @@
* via a set of 4 "Interrupt Controller Registers" (ICR). There is a
* loose mapping of vector number to register and internal bits, but
* a table is the easiest and quickest way to map them.
+ *
+ * Note that the external interrupts are edge triggered (unlike the
+ * internal interrupt sources which are level triggered). Which means
+ * they also need acknowledgeing via acknowledge bits.
*/
struct irqmap {
unsigned char icr;
@@ -68,6 +73,11 @@ static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
/*MCF_IRQ_SWTO*/ { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
};
+/*
+ * The act of masking the interrupt also has a side effect of 'ack'ing
+ * an interrupt on this irq (for the external irqs). So this mask function
+ * is also an ack_mask function.
+ */
static void intc_irq_mask(unsigned int irq)
{
if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
@@ -95,7 +105,9 @@ static void intc_irq_ack(unsigned int irq)
irq -= MCFINT_VECBASE;
if (intc_irqmap[irq].ack) {
u32 v;
- v = 0xd << intc_irqmap[irq].index;
+ v = readl(MCF_MBAR + intc_irqmap[irq].icr);
+ v &= (0x7 << intc_irqmap[irq].index);
+ v |= (0x8 << intc_irqmap[irq].index);
writel(v, MCF_MBAR + intc_irqmap[irq].icr);
}
}
@@ -103,21 +115,47 @@ static void intc_irq_ack(unsigned int irq)
static int intc_irq_set_type(unsigned int irq, unsigned int type)
{
- /* We can set the edge type here for external interrupts */
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+ irq -= MCFINT_VECBASE;
+ if (intc_irqmap[irq].ack) {
+ u32 v;
+ v = readl(MCF_MBAR + MCFSIM_PITR);
+ if (type == IRQ_TYPE_EDGE_FALLING)
+ v &= ~(0x1 << (32 - irq));
+ else
+ v |= (0x1 << (32 - irq));
+ writel(v, MCF_MBAR + MCFSIM_PITR);
+ }
+ }
return 0;
}
+/*
+ * Simple flow handler to deal with the external edge triggered interrupts.
+ * We need to be careful with the masking/acking due to the side effects
+ * of masking an interrupt.
+ */
+static void intc_external_irq(unsigned int irq, struct irq_desc *desc)
+{
+ kstat_incr_irqs_this_cpu(irq, desc);
+ desc->status |= IRQ_INPROGRESS;
+ desc->chip->ack(irq);
+ handle_IRQ_event(irq, desc->action);
+ desc->status &= ~IRQ_INPROGRESS;
+}
+
static struct irq_chip intc_irq_chip = {
.name = "CF-INTC",
.mask = intc_irq_mask,
.unmask = intc_irq_unmask,
+ .mask_ack = intc_irq_mask,
.ack = intc_irq_ack,
.set_type = intc_irq_set_type,
};
void __init init_IRQ(void)
{
- int irq;
+ int irq, edge;
init_vectors();
@@ -128,11 +166,17 @@ void __init init_IRQ(void)
writel(0x88888888, MCF_MBAR + MCFSIM_ICR4);
for (irq = 0; (irq < NR_IRQS); irq++) {
- irq_desc[irq].status = IRQ_DISABLED;
- irq_desc[irq].action = NULL;
- irq_desc[irq].depth = 1;
- irq_desc[irq].chip = &intc_irq_chip;
- intc_irq_set_type(irq, 0);
+ set_irq_chip(irq, &intc_irq_chip);
+ edge = 0;
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX))
+ edge = intc_irqmap[irq - MCFINT_VECBASE].ack;
+ if (edge) {
+ set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+ set_irq_handler(irq, intc_external_irq);
+ } else {
+ set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+ set_irq_handler(irq, handle_level_irq);
+ }
}
}
diff --git a/arch/m68knommu/platform/527x/Makefile b/arch/m68knommu/platform/527x/Makefile
index 3d90e6d92459..6ac4b57370ea 100644
--- a/arch/m68knommu/platform/527x/Makefile
+++ b/arch/m68knommu/platform/527x/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/528x/Makefile b/arch/m68knommu/platform/528x/Makefile
index 3d90e6d92459..6ac4b57370ea 100644
--- a/arch/m68knommu/platform/528x/Makefile
+++ b/arch/m68knommu/platform/528x/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile
index 6de526976828..d4293b791f2e 100644
--- a/arch/m68knommu/platform/5307/Makefile
+++ b/arch/m68knommu/platform/5307/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/532x/Makefile b/arch/m68knommu/platform/532x/Makefile
index 4cc23245bcd1..ce01669399c6 100644
--- a/arch/m68knommu/platform/532x/Makefile
+++ b/arch/m68knommu/platform/532x/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5407/Makefile b/arch/m68knommu/platform/5407/Makefile
index dee62c5dbaa6..e83fe148eddc 100644
--- a/arch/m68knommu/platform/5407/Makefile
+++ b/arch/m68knommu/platform/5407/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/548x/Makefile b/arch/m68knommu/platform/548x/Makefile
new file mode 100644
index 000000000000..e6035e7a2d3f
--- /dev/null
+++ b/arch/m68knommu/platform/548x/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this, which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
+# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o
+
diff --git a/arch/m68knommu/platform/548x/config.c b/arch/m68knommu/platform/548x/config.c
new file mode 100644
index 000000000000..9888846bd1cf
--- /dev/null
+++ b/arch/m68knommu/platform/548x/config.c
@@ -0,0 +1,115 @@
+/***************************************************************************/
+
+/*
+ * linux/arch/m68knommu/platform/548x/config.c
+ *
+ * Copyright (C) 2010, Philippe De Muyter <phdm@macqel.be>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/m548xsim.h>
+#include <asm/mcfuart.h>
+#include <asm/m548xgpt.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m548x_uart_platform[] = {
+ {
+ .mapbase = MCF_MBAR + MCFUART_BASE1,
+ .irq = 64 + 35,
+ },
+ {
+ .mapbase = MCF_MBAR + MCFUART_BASE2,
+ .irq = 64 + 34,
+ },
+ {
+ .mapbase = MCF_MBAR + MCFUART_BASE3,
+ .irq = 64 + 33,
+ },
+ {
+ .mapbase = MCF_MBAR + MCFUART_BASE4,
+ .irq = 64 + 32,
+ },
+};
+
+static struct platform_device m548x_uart = {
+ .name = "mcfuart",
+ .id = 0,
+ .dev.platform_data = m548x_uart_platform,
+};
+
+static struct platform_device *m548x_devices[] __initdata = {
+ &m548x_uart,
+};
+
+
+/***************************************************************************/
+
+static void __init m548x_uart_init_line(int line, int irq)
+{
+ int rts_cts;
+
+ /* enable io pins */
+ switch (line) {
+ case 0:
+ rts_cts = 0; break;
+ case 1:
+ rts_cts = MCF_PAR_PSC_RTS_RTS; break;
+ case 2:
+ rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break;
+ case 3:
+ rts_cts = 0; break;
+ }
+ __raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD,
+ MCF_MBAR + MCF_PAR_PSC(line));
+}
+
+static void __init m548x_uarts_init(void)
+{
+ const int nrlines = ARRAY_SIZE(m548x_uart_platform);
+ int line;
+
+ for (line = 0; (line < nrlines); line++)
+ m548x_uart_init_line(line, m548x_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void mcf548x_reset(void)
+{
+ /* disable interrupts and enable the watchdog */
+ asm("movew #0x2700, %sr\n");
+ __raw_writel(0, MCF_MBAR + MCF_GPT_GMS0);
+ __raw_writel(MCF_GPT_GCIR_CNT(1), MCF_MBAR + MCF_GPT_GCIR0);
+ __raw_writel(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS(4),
+ MCF_MBAR + MCF_GPT_GMS0);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+ mach_reset = mcf548x_reset;
+ m548x_uarts_init();
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+
+ platform_add_devices(m548x_devices, ARRAY_SIZE(m548x_devices));
+ return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S
index 9d80d2c42866..27241e16a526 100644
--- a/arch/m68knommu/platform/68328/entry.S
+++ b/arch/m68knommu/platform/68328/entry.S
@@ -43,10 +43,10 @@ badsys:
jra ret_from_exception
do_trace:
- movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
+ movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
subql #4,%sp
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_enter
RESTORE_SWITCH_STACK
addql #4,%sp
movel %sp@(PT_OFF_ORIG_D0),%d1
@@ -57,10 +57,10 @@ do_trace:
lea sys_call_table, %a0
jbsr %a0@(%d1)
-1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */
+1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_leave
ret_from_signal:
RESTORE_SWITCH_STACK
@@ -71,16 +71,16 @@ ENTRY(system_call)
SAVE_ALL
/* save top of frame*/
- pea %sp@
- jbsr set_esp0
- addql #4,%sp
+ pea %sp@
+ jbsr set_esp0
+ addql #4,%sp
movel %sp@(PT_OFF_ORIG_D0),%d0
movel %sp,%d1 /* get thread_info pointer */
andl #-THREAD_SIZE,%d1
movel %d1,%a2
- btst #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS)
+ btst #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
jne do_trace
cmpl #NR_syscalls,%d0
jcc badsys
@@ -88,10 +88,10 @@ ENTRY(system_call)
lea sys_call_table,%a0
movel %a0@(%d0), %a0
jbsr %a0@
- movel %d0,%sp@(PT_OFF_D0) /* save the return value*/
+ movel %d0,%sp@(PT_OFF_D0) /* save the return value*/
ret_from_exception:
- btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel*/
+ btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel*/
jeq Luser_return /* if so, skip resched, signals*/
Lkernel_return:
@@ -133,7 +133,7 @@ Lreturn:
*/
inthandler1:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -144,7 +144,7 @@ inthandler1:
inthandler2:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -155,7 +155,7 @@ inthandler2:
inthandler3:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -166,7 +166,7 @@ inthandler3:
inthandler4:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -177,7 +177,7 @@ inthandler4:
inthandler5:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -188,7 +188,7 @@ inthandler5:
inthandler6:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -199,7 +199,7 @@ inthandler6:
inthandler7:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -210,7 +210,7 @@ inthandler7:
inthandler:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
diff --git a/arch/m68knommu/platform/68328/head-de2.S b/arch/m68knommu/platform/68328/head-de2.S
index 92d96456d363..f632fdcb93e9 100644
--- a/arch/m68knommu/platform/68328/head-de2.S
+++ b/arch/m68knommu/platform/68328/head-de2.S
@@ -1,11 +1,5 @@
-#if defined(CONFIG_RAM32MB)
-#define MEM_END 0x02000000 /* Memory size 32Mb */
-#elif defined(CONFIG_RAM16MB)
-#define MEM_END 0x01000000 /* Memory size 16Mb */
-#else
#define MEM_END 0x00800000 /* Memory size 8Mb */
-#endif
#undef CRT_DEBUG
diff --git a/arch/m68knommu/platform/68328/head-ram.S b/arch/m68knommu/platform/68328/head-ram.S
index 252b80b02038..7f1aeeacb219 100644
--- a/arch/m68knommu/platform/68328/head-ram.S
+++ b/arch/m68knommu/platform/68328/head-ram.S
@@ -67,33 +67,6 @@ pclp1:
beq pclp1
#endif /* DEBUG */
-#ifdef CONFIG_RELOCATE
- /* Copy me to RAM */
- moveal #__rom_start, %a0
- moveal #_stext, %a1
- moveal #_edata, %a2
-
- /* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
- movel %a0@+, %d0
- movel %d0, %a1@+
- cmpal %a1, %a2
- bhi LD1
-
-#ifdef DEBUG
- moveq #74, %d7 /* 'J' */
- moveb %d7,0xfffff907 /* No absolute addresses */
-pclp2:
- movew 0xfffff906, %d7
- andw #0x2000, %d7
- beq pclp2
-#endif /* DEBUG */
- /* jump into the RAM copy */
- jmp ram_jump
-ram_jump:
-
-#endif /* CONFIG_RELOCATE */
-
#ifdef DEBUG
moveq #82, %d7 /* 'R' */
moveb %d7,0xfffff907 /* No absolute addresses */
diff --git a/arch/m68knommu/platform/68328/ints.c b/arch/m68knommu/platform/68328/ints.c
index b91ee85d4b5d..865852806a17 100644
--- a/arch/m68knommu/platform/68328/ints.c
+++ b/arch/m68knommu/platform/68328/ints.c
@@ -179,10 +179,8 @@ void __init init_IRQ(void)
IMR = ~0;
for (i = 0; (i < NR_IRQS); i++) {
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].action = NULL;
- irq_desc[i].depth = 1;
- irq_desc[i].chip = &intc_irq_chip;
+ set_irq_chip(irq, &intc_irq_chip);
+ set_irq_handler(irq, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/68360/entry.S b/arch/m68knommu/platform/68360/entry.S
index 6d3460a39cac..c131c6e1d92d 100644
--- a/arch/m68knommu/platform/68360/entry.S
+++ b/arch/m68knommu/platform/68360/entry.S
@@ -42,7 +42,7 @@ do_trace:
movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
subql #4,%sp
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_enter
RESTORE_SWITCH_STACK
addql #4,%sp
movel %sp@(PT_OFF_ORIG_D0),%d1
@@ -56,7 +56,7 @@ do_trace:
1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_leave
ret_from_signal:
RESTORE_SWITCH_STACK
@@ -71,7 +71,12 @@ ENTRY(system_call)
jbsr set_esp0
addql #4,%sp
- btst #PF_TRACESYS_BIT,%a2@(TASK_FLAGS+PF_TRACESYS_OFF)
+ movel %sp@(PT_OFF_ORIG_D0),%d0
+
+ movel %sp,%d1 /* get thread_info pointer */
+ andl #-THREAD_SIZE,%d1
+ movel %d1,%a2
+ btst #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
jne do_trace
cmpl #NR_syscalls,%d0
jcc badsys
@@ -124,7 +129,7 @@ Lreturn:
*/
inthandler:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and.l #0x3ff, %d0
lsr.l #0x02, %d0
diff --git a/arch/m68knommu/platform/68360/ints.c b/arch/m68knommu/platform/68360/ints.c
index 6f22970d8c20..ad96ab1051f0 100644
--- a/arch/m68knommu/platform/68360/ints.c
+++ b/arch/m68knommu/platform/68360/ints.c
@@ -132,10 +132,8 @@ void init_IRQ(void)
pquicc->intr_cimr = 0x00000000;
for (i = 0; (i < NR_IRQS); i++) {
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].action = NULL;
- irq_desc[i].depth = 1;
- irq_desc[i].chip = &intc_irq_chip;
+ set_irq_chip(irq, &intc_irq_chip);
+ set_irq_handler(irq, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/68VZ328/config.c b/arch/m68knommu/platform/68VZ328/config.c
index fc5c63054e98..eabaabe8af36 100644
--- a/arch/m68knommu/platform/68VZ328/config.c
+++ b/arch/m68knommu/platform/68VZ328/config.c
@@ -90,11 +90,6 @@ static void init_hardware(char *command, int size)
PDIQEG &= ~PD(1);
PDIRQEN |= PD(1); /* IRQ enabled */
-#ifdef CONFIG_68328_SERIAL_UART2
- /* Enable RXD TXD port bits to enable UART2 */
- PJSEL &= ~(PJ(5) | PJ(4));
-#endif
-
#ifdef CONFIG_INIT_LCD
/* initialize LCD controller */
LSSA = (long) screen_bits;
diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68knommu/platform/coldfire/Makefile
index f72a0e5d9996..45f501fa4525 100644
--- a/arch/m68knommu/platform/coldfire/Makefile
+++ b/arch/m68knommu/platform/coldfire/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
@@ -26,6 +26,7 @@ obj-$(CONFIG_M528x) += pit.o intc-2.o
obj-$(CONFIG_M5307) += timers.o intc.o
obj-$(CONFIG_M532x) += timers.o intc-simr.o
obj-$(CONFIG_M5407) += timers.o intc.o
+obj-$(CONFIG_M548x) += sltimers.o intc-2.o
obj-y += pinmux.o gpio.o
extra-y := head.o
diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68knommu/platform/coldfire/entry.S
index cd79d7e92ce6..5e92bed94b7e 100644
--- a/arch/m68knommu/platform/coldfire/entry.S
+++ b/arch/m68knommu/platform/coldfire/entry.S
@@ -88,7 +88,7 @@ ENTRY(system_call)
movel %d2,PT_OFF_D0(%sp) /* on syscall entry */
subql #4,%sp
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_enter
RESTORE_SWITCH_STACK
addql #4,%sp
movel %d3,%a0
@@ -96,7 +96,7 @@ ENTRY(system_call)
movel %d0,%sp@(PT_OFF_D0) /* save the return value */
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_leave
ret_from_signal:
RESTORE_SWITCH_STACK
diff --git a/arch/m68knommu/platform/coldfire/intc-2.c b/arch/m68knommu/platform/coldfire/intc-2.c
index 5598c8b8661f..85daa2b3001a 100644
--- a/arch/m68knommu/platform/coldfire/intc-2.c
+++ b/arch/m68knommu/platform/coldfire/intc-2.c
@@ -1,5 +1,11 @@
/*
- * intc-1.c
+ * intc-2.c
+ *
+ * General interrupt controller code for the many ColdFire cores that use
+ * interrupt controllers with 63 interrupt sources, organized as 56 fully-
+ * programmable + 7 fixed-level interrupt sources. This includes the 523x
+ * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
+ * controllers, and the 547x and 548x families which have only one of them.
*
* (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
*
@@ -19,21 +25,37 @@
#include <asm/traps.h>
/*
- * Each vector needs a unique priority and level asscoiated with it.
+ * Bit definitions for the ICR family of registers.
+ */
+#define MCFSIM_ICR_LEVEL(l) ((l)<<3) /* Level l intr */
+#define MCFSIM_ICR_PRI(p) (p) /* Priority p intr */
+
+/*
+ * Each vector needs a unique priority and level associated with it.
* We don't really care so much what they are, we don't rely on the
- * tranditional priority interrupt scheme of the m68k/ColdFire.
+ * traditional priority interrupt scheme of the m68k/ColdFire.
*/
-static u8 intc_intpri = 0x36;
+static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6);
+
+#ifdef MCFICM_INTC1
+#define NR_VECS 128
+#else
+#define NR_VECS 64
+#endif
static void intc_irq_mask(unsigned int irq)
{
- if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) {
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) {
unsigned long imraddr;
u32 val, imrbit;
irq -= MCFINT_VECBASE;
imraddr = MCF_IPSBAR;
+#ifdef MCFICM_INTC1
imraddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+ imraddr += MCFICM_INTC0;
+#endif
imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL;
imrbit = 0x1 << (irq & 0x1f);
@@ -44,13 +66,17 @@ static void intc_irq_mask(unsigned int irq)
static void intc_irq_unmask(unsigned int irq)
{
- if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) {
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) {
unsigned long intaddr, imraddr, icraddr;
u32 val, imrbit;
irq -= MCFINT_VECBASE;
intaddr = MCF_IPSBAR;
+#ifdef MCFICM_INTC1
intaddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+ intaddr += MCFICM_INTC0;
+#endif
imraddr = intaddr + ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL);
icraddr = intaddr + MCFINTC_ICR0 + (irq & 0x3f);
imrbit = 0x1 << (irq & 0x1f);
@@ -67,10 +93,16 @@ static void intc_irq_unmask(unsigned int irq)
}
}
+static int intc_irq_set_type(unsigned int irq, unsigned int type)
+{
+ return 0;
+}
+
static struct irq_chip intc_irq_chip = {
.name = "CF-INTC",
.mask = intc_irq_mask,
.unmask = intc_irq_unmask,
+ .set_type = intc_irq_set_type,
};
void __init init_IRQ(void)
@@ -81,13 +113,14 @@ void __init init_IRQ(void)
/* Mask all interrupt sources */
__raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
+#ifdef MCFICM_INTC1
__raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_IMRL);
+#endif
for (irq = 0; (irq < NR_IRQS); irq++) {
- irq_desc[irq].status = IRQ_DISABLED;
- irq_desc[irq].action = NULL;
- irq_desc[irq].depth = 1;
- irq_desc[irq].chip = &intc_irq_chip;
+ set_irq_chip(irq, &intc_irq_chip);
+ set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+ set_irq_handler(irq, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/coldfire/intc-simr.c b/arch/m68knommu/platform/coldfire/intc-simr.c
index 1b01e79c2f63..bb7048636140 100644
--- a/arch/m68knommu/platform/coldfire/intc-simr.c
+++ b/arch/m68knommu/platform/coldfire/intc-simr.c
@@ -1,6 +1,8 @@
/*
* intc-simr.c
*
+ * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts.
+ *
* (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -68,11 +70,9 @@ void __init init_IRQ(void)
__raw_writeb(0xff, MCFINTC1_SIMR);
for (irq = 0; (irq < NR_IRQS); irq++) {
- irq_desc[irq].status = IRQ_DISABLED;
- irq_desc[irq].action = NULL;
- irq_desc[irq].depth = 1;
- irq_desc[irq].chip = &intc_irq_chip;
- intc_irq_set_type(irq, 0);
+ set_irq_chip(irq, &intc_irq_chip);
+ set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+ set_irq_handler(irq, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/coldfire/intc.c b/arch/m68knommu/platform/coldfire/intc.c
index a4560c86db71..60d2fcbe182b 100644
--- a/arch/m68knommu/platform/coldfire/intc.c
+++ b/arch/m68knommu/platform/coldfire/intc.c
@@ -143,11 +143,9 @@ void __init init_IRQ(void)
mcf_maskimr(0xffffffff);
for (irq = 0; (irq < NR_IRQS); irq++) {
- irq_desc[irq].status = IRQ_DISABLED;
- irq_desc[irq].action = NULL;
- irq_desc[irq].depth = 1;
- irq_desc[irq].chip = &intc_irq_chip;
- intc_irq_set_type(irq, 0);
+ set_irq_chip(irq, &intc_irq_chip);
+ set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+ set_irq_handler(irq, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/coldfire/sltimers.c b/arch/m68knommu/platform/coldfire/sltimers.c
new file mode 100644
index 000000000000..0a1b937c3e18
--- /dev/null
+++ b/arch/m68knommu/platform/coldfire/sltimers.c
@@ -0,0 +1,145 @@
+/***************************************************************************/
+
+/*
+ * sltimers.c -- generic ColdFire slice timer support.
+ *
+ * Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be>
+ * based on
+ * timers.c -- generic ColdFire hardware timer support.
+ * Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <asm/io.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfslt.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+#ifdef CONFIG_HIGHPROFILE
+
+/*
+ * By default use Slice Timer 1 as the profiler clock timer.
+ */
+#define PA(a) (MCF_MBAR + MCFSLT_TIMER1 + (a))
+
+/*
+ * Choose a reasonably fast profile timer. Make it an odd value to
+ * try and get good coverage of kernel operations.
+ */
+#define PROFILEHZ 1013
+
+irqreturn_t mcfslt_profile_tick(int irq, void *dummy)
+{
+ /* Reset Slice Timer 1 */
+ __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR));
+ if (current->pid)
+ profile_tick(CPU_PROFILING);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction mcfslt_profile_irq = {
+ .name = "profile timer",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = mcfslt_profile_tick,
+};
+
+void mcfslt_profile_init(void)
+{
+ printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",
+ PROFILEHZ);
+
+ setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);
+
+ /* Set up TIMER 2 as high speed profile clock */
+ __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));
+ __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+ PA(MCFSLT_SCR));
+
+}
+
+#endif /* CONFIG_HIGHPROFILE */
+
+/***************************************************************************/
+
+/*
+ * By default use Slice Timer 0 as the system clock timer.
+ */
+#define TA(a) (MCF_MBAR + MCFSLT_TIMER0 + (a))
+
+static u32 mcfslt_cycles_per_jiffy;
+static u32 mcfslt_cnt;
+
+static irqreturn_t mcfslt_tick(int irq, void *dummy)
+{
+ /* Reset Slice Timer 0 */
+ __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
+ mcfslt_cnt += mcfslt_cycles_per_jiffy;
+ return arch_timer_interrupt(irq, dummy);
+}
+
+static struct irqaction mcfslt_timer_irq = {
+ .name = "timer",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = mcfslt_tick,
+};
+
+static cycle_t mcfslt_read_clk(struct clocksource *cs)
+{
+ unsigned long flags;
+ u32 cycles;
+ u16 scnt;
+
+ local_irq_save(flags);
+ scnt = __raw_readl(TA(MCFSLT_SCNT));
+ cycles = mcfslt_cnt;
+ local_irq_restore(flags);
+
+ /* substract because slice timers count down */
+ return cycles - scnt;
+}
+
+static struct clocksource mcfslt_clk = {
+ .name = "slt",
+ .rating = 250,
+ .read = mcfslt_read_clk,
+ .shift = 20,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+void hw_timer_init(void)
+{
+ mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
+ /*
+ * The coldfire slice timer (SLT) runs from STCNT to 0 included,
+ * then STCNT again and so on. It counts thus actually
+ * STCNT + 1 steps for 1 tick, not STCNT. So if you want
+ * n cycles, initialize STCNT with n - 1.
+ */
+ __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT));
+ __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+ TA(MCFSLT_SCR));
+ /* initialize mcfslt_cnt knowing that slice timers count down */
+ mcfslt_cnt = mcfslt_cycles_per_jiffy;
+
+ setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
+
+ mcfslt_clk.mult = clocksource_hz2mult(MCF_BUSCLK, mcfslt_clk.shift);
+ clocksource_register(&mcfslt_clk);
+
+#ifdef CONFIG_HIGHPROFILE
+ mcfslt_profile_init();
+#endif
+}
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c
index 427b13b4740f..bacbd3d41ec7 100644
--- a/arch/microblaze/kernel/prom.c
+++ b/arch/microblaze/kernel/prom.c
@@ -42,11 +42,6 @@
#include <asm/sections.h>
#include <asm/pci-bridge.h>
-void __init early_init_dt_scan_chosen_arch(unsigned long node)
-{
- /* No Microblaze specific code here */
-}
-
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
memblock_add(base, size);
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 784cf822963a..46cae2b163e4 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2128,6 +2128,13 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here.
+config USE_OF
+ bool "Flattened Device Tree support"
+ select OF
+ select OF_FLATTREE
+ help
+ Include support for flattened device tree machine descriptions.
+
endmenu
config LOCKDEP_SUPPORT
diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h
index dea4aed6478f..b003ed52ed17 100644
--- a/arch/mips/include/asm/irq.h
+++ b/arch/mips/include/asm/irq.h
@@ -16,6 +16,11 @@
#include <irq.h>
+static inline void irq_dispose_mapping(unsigned int virq)
+{
+ return;
+}
+
#ifdef CONFIG_I8259
static inline int irq_canonicalize(int irq)
{
diff --git a/arch/mips/include/asm/prom.h b/arch/mips/include/asm/prom.h
new file mode 100644
index 000000000000..f29b862d9db3
--- /dev/null
+++ b/arch/mips/include/asm/prom.h
@@ -0,0 +1,31 @@
+/*
+ * arch/mips/include/asm/prom.h
+ *
+ * Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __ASM_MIPS_PROM_H
+#define __ASM_MIPS_PROM_H
+
+#ifdef CONFIG_OF
+#include <asm/bootinfo.h>
+
+/* which is compatible with the flattened device tree (FDT) */
+#define cmd_line arcs_cmdline
+
+extern int early_init_dt_scan_memory_arch(unsigned long node,
+ const char *uname, int depth, void *data);
+
+extern int reserve_mem_mach(unsigned long addr, unsigned long size);
+extern void free_mem_mach(unsigned long addr, unsigned long size);
+
+extern void device_tree_init(void);
+#else /* CONFIG_OF */
+static inline void device_tree_init(void) { }
+#endif /* CONFIG_OF */
+
+#endif /* _ASM_MIPS_PROM_H */
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 06f848299785..80884983270d 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -96,6 +96,8 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o
+obj-$(CONFIG_OF) += prom.o
+
CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index 9a526ba6f257..802e6160f37e 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -103,7 +103,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
goto out_unlock;
- retval = security_task_setscheduler(p)
+ retval = security_task_setscheduler(p);
if (retval)
goto out_unlock;
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
new file mode 100644
index 000000000000..e000b278f024
--- /dev/null
+++ b/arch/mips/kernel/prom.c
@@ -0,0 +1,112 @@
+/*
+ * MIPS support for CONFIG_OF device tree support
+ *
+ * Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/bootmem.h>
+#include <linux/initrd.h>
+#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/page.h>
+#include <asm/prom.h>
+
+int __init early_init_dt_scan_memory_arch(unsigned long node,
+ const char *uname, int depth,
+ void *data)
+{
+ return early_init_dt_scan_memory(node, uname, depth, data);
+}
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+ return add_memory_region(base, size, BOOT_MEM_RAM);
+}
+
+int __init reserve_mem_mach(unsigned long addr, unsigned long size)
+{
+ return reserve_bootmem(addr, size, BOOTMEM_DEFAULT);
+}
+
+void __init free_mem_mach(unsigned long addr, unsigned long size)
+{
+ return free_bootmem(addr, size);
+}
+
+u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+ return virt_to_phys(
+ __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS))
+ );
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+ unsigned long end)
+{
+ initrd_start = (unsigned long)__va(start);
+ initrd_end = (unsigned long)__va(end);
+ initrd_below_start_ok = 1;
+}
+#endif
+
+/*
+ * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
+ *
+ * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
+ * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not
+ * supported.
+ */
+unsigned int irq_create_of_mapping(struct device_node *controller,
+ const u32 *intspec, unsigned int intsize)
+{
+ return intspec[0];
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
+
+void __init early_init_devtree(void *params)
+{
+ /* Setup flat device-tree pointer */
+ initial_boot_params = params;
+
+ /* Retrieve various informations from the /chosen node of the
+ * device-tree, including the platform type, initrd location and
+ * size, and more ...
+ */
+ of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
+
+ /* Scan memory nodes */
+ of_scan_flat_dt(early_init_dt_scan_root, NULL);
+ of_scan_flat_dt(early_init_dt_scan_memory_arch, NULL);
+}
+
+void __init device_tree_init(void)
+{
+ unsigned long base, size;
+
+ if (!initial_boot_params)
+ return;
+
+ base = virt_to_phys((void *)initial_boot_params);
+ size = initial_boot_params->totalsize;
+
+ /* Before we do anything, lets reserve the dt blob */
+ reserve_mem_mach(base, size);
+
+ unflatten_device_tree();
+
+ /* free the space reserved for the dt blob */
+ free_mem_mach(base, size);
+}
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 85aef3fc6716..a6b900f2962b 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -31,6 +31,7 @@
#include <asm/setup.h>
#include <asm/smp-ops.h>
#include <asm/system.h>
+#include <asm/prom.h>
struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly;
@@ -487,6 +488,7 @@ static void __init arch_mem_init(char **cmdline_p)
}
bootmem_init();
+ device_tree_init();
sparse_init();
paging_init();
}
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 9b626cfffce1..f62efdfd1769 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -162,13 +162,10 @@ static int ibmebus_create_device(struct device_node *dn)
dev->dev.bus = &ibmebus_bus_type;
dev->dev.archdata.dma_ops = &ibmebus_dma_ops;
- ret = of_device_register(dev);
- if (ret) {
- of_device_free(dev);
- return ret;
- }
-
- return 0;
+ ret = of_device_add(dev);
+ if (ret)
+ platform_device_put(dev);
+ return ret;
}
static int ibmebus_create_devices(const struct of_device_id *matches)
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index c1fd0f9658fd..c834757bebc0 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -52,14 +52,14 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
phys_addr_t taddr, unsigned long irq,
upf_t flags, int irq_check_parent)
{
- const u32 *clk, *spd;
+ const __be32 *clk, *spd;
u32 clock = BASE_BAUD * 16;
int index;
/* get clock freq. if present */
clk = of_get_property(np, "clock-frequency", NULL);
if (clk && *clk)
- clock = *clk;
+ clock = be32_to_cpup(clk);
/* get default speed if present */
spd = of_get_property(np, "current-speed", NULL);
@@ -109,7 +109,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
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;
+ legacy_serial_infos[index].speed = spd ? be32_to_cpup(spd) : 0;
legacy_serial_infos[index].irq_check_parent = irq_check_parent;
printk(KERN_DEBUG "Found legacy serial port %d for %s\n",
@@ -168,7 +168,7 @@ static int __init add_legacy_soc_port(struct device_node *np,
static int __init add_legacy_isa_port(struct device_node *np,
struct device_node *isa_brg)
{
- const u32 *reg;
+ const __be32 *reg;
const char *typep;
int index = -1;
u64 taddr;
@@ -181,7 +181,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
return -1;
/* Verify it's an IO port, we don't support anything else */
- if (!(reg[0] & 0x00000001))
+ if (!(be32_to_cpu(reg[0]) & 0x00000001))
return -1;
/* Now look for an "ibm,aix-loc" property that gives us ordering
@@ -202,7 +202,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
taddr = 0;
/* Add port, irq will be dealt with later */
- return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr,
+ return add_legacy_port(np, index, UPIO_PORT, be32_to_cpu(reg[1]), taddr,
NO_IRQ, UPF_BOOT_AUTOCONF, 0);
}
@@ -251,9 +251,9 @@ static int __init add_legacy_pci_port(struct device_node *np,
* we get to their "reg" property
*/
if (np != pci_dev) {
- const u32 *reg = of_get_property(np, "reg", NULL);
- if (reg && (*reg < 4))
- index = lindex = *reg;
+ const __be32 *reg = of_get_property(np, "reg", NULL);
+ if (reg && (be32_to_cpup(reg) < 4))
+ index = lindex = be32_to_cpup(reg);
}
/* Local index means it's the Nth port in the PCI chip. Unfortunately
@@ -507,7 +507,7 @@ static int __init check_legacy_serial_console(void)
struct device_node *prom_stdout = NULL;
int i, speed = 0, offset = 0;
const char *name;
- const u32 *spd;
+ const __be32 *spd;
DBG(" -> check_legacy_serial_console()\n");
@@ -547,7 +547,7 @@ static int __init check_legacy_serial_console(void)
}
spd = of_get_property(prom_stdout, "current-speed", NULL);
if (spd)
- speed = *spd;
+ speed = be32_to_cpup(spd);
if (strcmp(name, "serial") != 0)
goto not_found;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index c3c6a8857544..9e3132db718b 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -364,10 +364,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
return 0;
}
-void __init early_init_dt_scan_chosen_arch(unsigned long node)
+int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname,
+ int depth, void *data)
{
unsigned long *lprop;
+ /* Use common scan routine to determine if this is the chosen node */
+ if (early_init_dt_scan_chosen(node, uname, depth, data) == 0)
+ return 0;
+
#ifdef CONFIG_PPC64
/* check if iommu is forced on or off */
if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
@@ -399,6 +404,9 @@ void __init early_init_dt_scan_chosen_arch(unsigned long node)
if (lprop)
crashk_res.end = crashk_res.start + *lprop - 1;
#endif
+
+ /* break now */
+ return 1;
}
#ifdef CONFIG_PPC_PSERIES
@@ -683,7 +691,7 @@ void __init early_init_devtree(void *params)
* device-tree, including the platform type, initrd location and
* size, TCE reserve, and more ...
*/
- of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
+ of_scan_flat_dt(early_init_dt_scan_chosen_ppc, NULL);
/* Scan memory nodes and rebuild MEMBLOCKs */
memblock_init();
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 35b6879628a0..0f40fc35d0a2 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -24,6 +24,7 @@ config SUPERH
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
select HAVE_SYSCALL_TRACEPOINTS
+ select HAVE_REGS_AND_STACK_ACCESS_API
select RTC_LIB
select GENERIC_ATOMIC64
help
@@ -46,7 +47,7 @@ config SUPERH32
select HAVE_ARCH_KGDB
select HAVE_HW_BREAKPOINT
select HAVE_MIXED_BREAKPOINTS_REGS
- select PERF_EVENTS if HAVE_HW_BREAKPOINT
+ select PERF_EVENTS
select ARCH_HIBERNATION_POSSIBLE if MMU
config SUPERH64
@@ -471,6 +472,7 @@ config CPU_SUBTYPE_SHX3
select CPU_SH4A
select CPU_SHX3
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+ select ARCH_REQUIRE_GPIOLIB
# SH4AL-DSP Processor Support
@@ -575,7 +577,7 @@ config SH_CLK_CPG
config SH_CLK_CPG_LEGACY
depends on SH_CLK_CPG
def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE && \
- !CPU_SUBTYPE_SH7786
+ !CPU_SHX3 && !CPU_SUBTYPE_SH7757
config SH_CLK_MD
int "CPU Mode Pin Setting"
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 07b35ca2f644..9c94711aa6ca 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -155,6 +155,8 @@ config SH_SDK7786
depends on CPU_SUBTYPE_SH7786
select SYS_SUPPORTS_PCI
select NO_IOPORT if !PCI
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select HAVE_SRAM_POOL
help
Select SDK7786 if configuring for a Renesas Technology Europe
SH7786-65nm board.
@@ -165,6 +167,11 @@ config SH_HIGHLANDER
select SYS_SUPPORTS_PCI
select IO_TRAPPED if MMU
+config SH_SH7757LCR
+ bool "SH7757LCR"
+ depends on CPU_SUBTYPE_SH7757
+ select ARCH_REQUIRE_GPIOLIB
+
config SH_SH7785LCR
bool "SH7785LCR"
depends on CPU_SUBTYPE_SH7785
@@ -309,6 +316,17 @@ config SH_POLARIS
help
Select if configuring for an SMSC Polaris development board
+config SH_SH2007
+ bool "SH-2007 board"
+ select NO_IOPORT
+ depends on CPU_SUBTYPE_SH7780
+ help
+ SH-2007 is a single-board computer based around SH7780 chip
+ intended for embedded applications.
+ It has an Ethernet interface (SMC9118), direct connected
+ Compact Flash socket, two serial ports and PC-104 bus.
+ More information at <http://sh2000.sh-linux.org>.
+
endmenu
source "arch/sh/boards/mach-r2d/Kconfig"
diff --git a/arch/sh/boards/Makefile b/arch/sh/boards/Makefile
index 4f90f9b7a922..38ef655cc0f0 100644
--- a/arch/sh/boards/Makefile
+++ b/arch/sh/boards/Makefile
@@ -2,6 +2,7 @@
# Specific board support, not covered by a mach group.
#
obj-$(CONFIG_SH_MAGIC_PANEL_R2) += board-magicpanelr2.o
+obj-$(CONFIG_SH_SH2007) += board-sh2007.o
obj-$(CONFIG_SH_SH7785LCR) += board-sh7785lcr.o
obj-$(CONFIG_SH_URQUELL) += board-urquell.o
obj-$(CONFIG_SH_SHMIN) += board-shmin.o
@@ -9,3 +10,4 @@ obj-$(CONFIG_SH_EDOSK7760) += board-edosk7760.o
obj-$(CONFIG_SH_ESPT) += board-espt.o
obj-$(CONFIG_SH_POLARIS) += board-polaris.o
obj-$(CONFIG_SH_TITAN) += board-titan.o
+obj-$(CONFIG_SH_SH7757LCR) += board-sh7757lcr.o
diff --git a/arch/sh/boards/board-sh2007.c b/arch/sh/boards/board-sh2007.c
new file mode 100644
index 000000000000..b90b78f6a829
--- /dev/null
+++ b/arch/sh/boards/board-sh2007.c
@@ -0,0 +1,133 @@
+/*
+ * SH-2007 board support.
+ *
+ * Copyright (C) 2003, 2004 SUGIOKA Toshinobu
+ * Copyright (C) 2010 Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/smsc911x.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/io.h>
+#include <asm/machvec.h>
+#include <mach/sh2007.h>
+
+struct smsc911x_platform_config smc911x_info = {
+ .flags = SMSC911X_USE_32BIT,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct resource smsc9118_0_resources[] = {
+ [0] = {
+ .start = SMC0_BASE,
+ .end = SMC0_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x240),
+ .end = evt2irq(0x240),
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct resource smsc9118_1_resources[] = {
+ [0] = {
+ .start = SMC1_BASE,
+ .end = SMC1_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x280),
+ .end = evt2irq(0x280),
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device smsc9118_0_device = {
+ .name = "smsc911x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smsc9118_0_resources),
+ .resource = smsc9118_0_resources,
+ .dev = {
+ .platform_data = &smc911x_info,
+ },
+};
+
+static struct platform_device smsc9118_1_device = {
+ .name = "smsc911x",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(smsc9118_1_resources),
+ .resource = smsc9118_1_resources,
+ .dev = {
+ .platform_data = &smc911x_info,
+ },
+};
+
+static struct resource cf_resources[] = {
+ [0] = {
+ .start = CF_BASE + CF_OFFSET,
+ .end = CF_BASE + CF_OFFSET + 0x0f,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = CF_BASE + CF_OFFSET + 0x206,
+ .end = CF_BASE + CF_OFFSET + 0x20f,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = evt2irq(0x2c0),
+ .end = evt2irq(0x2c0),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cf_device = {
+ .name = "pata_platform",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(cf_resources),
+ .resource = cf_resources,
+};
+
+static struct platform_device *sh2007_devices[] __initdata = {
+ &smsc9118_0_device,
+ &smsc9118_1_device,
+ &cf_device,
+};
+
+static int __init sh2007_io_init(void)
+{
+ platform_add_devices(sh2007_devices, ARRAY_SIZE(sh2007_devices));
+ return 0;
+}
+subsys_initcall(sh2007_io_init);
+
+static void __init sh2007_init_irq(void)
+{
+ plat_irq_setup_pins(IRQ_MODE_IRQ);
+}
+
+/*
+ * Initialize the board
+ */
+static void __init sh2007_setup(char **cmdline_p)
+{
+ printk(KERN_INFO "SH-2007 Setup...");
+
+ /* setup wait control registers for area 5 */
+ __raw_writel(CS5BCR_D, CS5BCR);
+ __raw_writel(CS5WCR_D, CS5WCR);
+ __raw_writel(CS5PCR_D, CS5PCR);
+
+ printk(KERN_INFO " done.\n");
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_sh2007 __initmv = {
+ .mv_setup = sh2007_setup,
+ .mv_name = "sh2007",
+ .mv_init_irq = sh2007_init_irq,
+};
diff --git a/arch/sh/boards/board-sh7757lcr.c b/arch/sh/boards/board-sh7757lcr.c
new file mode 100644
index 000000000000..c475f1056ab4
--- /dev/null
+++ b/arch/sh/boards/board-sh7757lcr.c
@@ -0,0 +1,374 @@
+/*
+ * Renesas R0P7757LC0012RL Support.
+ *
+ * Copyright (C) 2009 - 2010 Renesas Solutions Corp.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/io.h>
+#include <cpu/sh7757.h>
+#include <asm/sh_eth.h>
+#include <asm/heartbeat.h>
+
+static struct resource heartbeat_resource = {
+ .start = 0xffec005c, /* PUDR */
+ .end = 0xffec005c,
+ .flags = IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
+};
+
+static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3 };
+
+static struct heartbeat_data heartbeat_data = {
+ .bit_pos = heartbeat_bit_pos,
+ .nr_bits = ARRAY_SIZE(heartbeat_bit_pos),
+ .flags = HEARTBEAT_INVERTED,
+};
+
+static struct platform_device heartbeat_device = {
+ .name = "heartbeat",
+ .id = -1,
+ .dev = {
+ .platform_data = &heartbeat_data,
+ },
+ .num_resources = 1,
+ .resource = &heartbeat_resource,
+};
+
+/* Fast Ethernet */
+static struct resource sh_eth0_resources[] = {
+ {
+ .start = 0xfef00000,
+ .end = 0xfef001ff,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = 84,
+ .end = 84,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sh_eth_plat_data sh7757_eth0_pdata = {
+ .phy = 1,
+ .edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device sh7757_eth0_device = {
+ .name = "sh-eth",
+ .resource = sh_eth0_resources,
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sh_eth0_resources),
+ .dev = {
+ .platform_data = &sh7757_eth0_pdata,
+ },
+};
+
+static struct resource sh_eth1_resources[] = {
+ {
+ .start = 0xfef00800,
+ .end = 0xfef009ff,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = 84,
+ .end = 84,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sh_eth_plat_data sh7757_eth1_pdata = {
+ .phy = 1,
+ .edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device sh7757_eth1_device = {
+ .name = "sh-eth",
+ .resource = sh_eth1_resources,
+ .id = 1,
+ .num_resources = ARRAY_SIZE(sh_eth1_resources),
+ .dev = {
+ .platform_data = &sh7757_eth1_pdata,
+ },
+};
+
+static struct platform_device *sh7757lcr_devices[] __initdata = {
+ &heartbeat_device,
+ &sh7757_eth0_device,
+ &sh7757_eth1_device,
+};
+
+static int __init sh7757lcr_devices_setup(void)
+{
+ /* RGMII (PTA) */
+ gpio_request(GPIO_FN_ET0_MDC, NULL);
+ gpio_request(GPIO_FN_ET0_MDIO, NULL);
+ gpio_request(GPIO_FN_ET1_MDC, NULL);
+ gpio_request(GPIO_FN_ET1_MDIO, NULL);
+
+ /* ONFI (PTB, PTZ) */
+ gpio_request(GPIO_FN_ON_NRE, NULL);
+ gpio_request(GPIO_FN_ON_NWE, NULL);
+ gpio_request(GPIO_FN_ON_NWP, NULL);
+ gpio_request(GPIO_FN_ON_NCE0, NULL);
+ gpio_request(GPIO_FN_ON_R_B0, NULL);
+ gpio_request(GPIO_FN_ON_ALE, NULL);
+ gpio_request(GPIO_FN_ON_CLE, NULL);
+
+ gpio_request(GPIO_FN_ON_DQ7, NULL);
+ gpio_request(GPIO_FN_ON_DQ6, NULL);
+ gpio_request(GPIO_FN_ON_DQ5, NULL);
+ gpio_request(GPIO_FN_ON_DQ4, NULL);
+ gpio_request(GPIO_FN_ON_DQ3, NULL);
+ gpio_request(GPIO_FN_ON_DQ2, NULL);
+ gpio_request(GPIO_FN_ON_DQ1, NULL);
+ gpio_request(GPIO_FN_ON_DQ0, NULL);
+
+ /* IRQ8 to 0 (PTB, PTC) */
+ gpio_request(GPIO_FN_IRQ8, NULL);
+ gpio_request(GPIO_FN_IRQ7, NULL);
+ gpio_request(GPIO_FN_IRQ6, NULL);
+ gpio_request(GPIO_FN_IRQ5, NULL);
+ gpio_request(GPIO_FN_IRQ4, NULL);
+ gpio_request(GPIO_FN_IRQ3, NULL);
+ gpio_request(GPIO_FN_IRQ2, NULL);
+ gpio_request(GPIO_FN_IRQ1, NULL);
+ gpio_request(GPIO_FN_IRQ0, NULL);
+
+ /* SPI0 (PTD) */
+ gpio_request(GPIO_FN_SP0_MOSI, NULL);
+ gpio_request(GPIO_FN_SP0_MISO, NULL);
+ gpio_request(GPIO_FN_SP0_SCK, NULL);
+ gpio_request(GPIO_FN_SP0_SCK_FB, NULL);
+ gpio_request(GPIO_FN_SP0_SS0, NULL);
+ gpio_request(GPIO_FN_SP0_SS1, NULL);
+ gpio_request(GPIO_FN_SP0_SS2, NULL);
+ gpio_request(GPIO_FN_SP0_SS3, NULL);
+
+ /* RMII 0/1 (PTE, PTF) */
+ gpio_request(GPIO_FN_RMII0_CRS_DV, NULL);
+ gpio_request(GPIO_FN_RMII0_TXD1, NULL);
+ gpio_request(GPIO_FN_RMII0_TXD0, NULL);
+ gpio_request(GPIO_FN_RMII0_TXEN, NULL);
+ gpio_request(GPIO_FN_RMII0_REFCLK, NULL);
+ gpio_request(GPIO_FN_RMII0_RXD1, NULL);
+ gpio_request(GPIO_FN_RMII0_RXD0, NULL);
+ gpio_request(GPIO_FN_RMII0_RX_ER, NULL);
+ gpio_request(GPIO_FN_RMII1_CRS_DV, NULL);
+ gpio_request(GPIO_FN_RMII1_TXD1, NULL);
+ gpio_request(GPIO_FN_RMII1_TXD0, NULL);
+ gpio_request(GPIO_FN_RMII1_TXEN, NULL);
+ gpio_request(GPIO_FN_RMII1_REFCLK, NULL);
+ gpio_request(GPIO_FN_RMII1_RXD1, NULL);
+ gpio_request(GPIO_FN_RMII1_RXD0, NULL);
+ gpio_request(GPIO_FN_RMII1_RX_ER, NULL);
+
+ /* eMMC (PTG) */
+ gpio_request(GPIO_FN_MMCCLK, NULL);
+ gpio_request(GPIO_FN_MMCCMD, NULL);
+ gpio_request(GPIO_FN_MMCDAT7, NULL);
+ gpio_request(GPIO_FN_MMCDAT6, NULL);
+ gpio_request(GPIO_FN_MMCDAT5, NULL);
+ gpio_request(GPIO_FN_MMCDAT4, NULL);
+ gpio_request(GPIO_FN_MMCDAT3, NULL);
+ gpio_request(GPIO_FN_MMCDAT2, NULL);
+ gpio_request(GPIO_FN_MMCDAT1, NULL);
+ gpio_request(GPIO_FN_MMCDAT0, NULL);
+
+ /* LPC (PTG, PTH, PTQ, PTU) */
+ gpio_request(GPIO_FN_SERIRQ, NULL);
+ gpio_request(GPIO_FN_LPCPD, NULL);
+ gpio_request(GPIO_FN_LDRQ, NULL);
+ gpio_request(GPIO_FN_WP, NULL);
+ gpio_request(GPIO_FN_FMS0, NULL);
+ gpio_request(GPIO_FN_LAD3, NULL);
+ gpio_request(GPIO_FN_LAD2, NULL);
+ gpio_request(GPIO_FN_LAD1, NULL);
+ gpio_request(GPIO_FN_LAD0, NULL);
+ gpio_request(GPIO_FN_LFRAME, NULL);
+ gpio_request(GPIO_FN_LRESET, NULL);
+ gpio_request(GPIO_FN_LCLK, NULL);
+ gpio_request(GPIO_FN_LGPIO7, NULL);
+ gpio_request(GPIO_FN_LGPIO6, NULL);
+ gpio_request(GPIO_FN_LGPIO5, NULL);
+ gpio_request(GPIO_FN_LGPIO4, NULL);
+
+ /* SPI1 (PTH) */
+ gpio_request(GPIO_FN_SP1_MOSI, NULL);
+ gpio_request(GPIO_FN_SP1_MISO, NULL);
+ gpio_request(GPIO_FN_SP1_SCK, NULL);
+ gpio_request(GPIO_FN_SP1_SCK_FB, NULL);
+ gpio_request(GPIO_FN_SP1_SS0, NULL);
+ gpio_request(GPIO_FN_SP1_SS1, NULL);
+
+ /* SDHI (PTI) */
+ gpio_request(GPIO_FN_SD_WP, NULL);
+ gpio_request(GPIO_FN_SD_CD, NULL);
+ gpio_request(GPIO_FN_SD_CLK, NULL);
+ gpio_request(GPIO_FN_SD_CMD, NULL);
+ gpio_request(GPIO_FN_SD_D3, NULL);
+ gpio_request(GPIO_FN_SD_D2, NULL);
+ gpio_request(GPIO_FN_SD_D1, NULL);
+ gpio_request(GPIO_FN_SD_D0, NULL);
+
+ /* SCIF3/4 (PTJ, PTW) */
+ gpio_request(GPIO_FN_RTS3, NULL);
+ gpio_request(GPIO_FN_CTS3, NULL);
+ gpio_request(GPIO_FN_TXD3, NULL);
+ gpio_request(GPIO_FN_RXD3, NULL);
+ gpio_request(GPIO_FN_RTS4, NULL);
+ gpio_request(GPIO_FN_RXD4, NULL);
+ gpio_request(GPIO_FN_TXD4, NULL);
+ gpio_request(GPIO_FN_CTS4, NULL);
+
+ /* SERMUX (PTK, PTL, PTO, PTV) */
+ gpio_request(GPIO_FN_COM2_TXD, NULL);
+ gpio_request(GPIO_FN_COM2_RXD, NULL);
+ gpio_request(GPIO_FN_COM2_RTS, NULL);
+ gpio_request(GPIO_FN_COM2_CTS, NULL);
+ gpio_request(GPIO_FN_COM2_DTR, NULL);
+ gpio_request(GPIO_FN_COM2_DSR, NULL);
+ gpio_request(GPIO_FN_COM2_DCD, NULL);
+ gpio_request(GPIO_FN_COM2_RI, NULL);
+ gpio_request(GPIO_FN_RAC_RXD, NULL);
+ gpio_request(GPIO_FN_RAC_RTS, NULL);
+ gpio_request(GPIO_FN_RAC_CTS, NULL);
+ gpio_request(GPIO_FN_RAC_DTR, NULL);
+ gpio_request(GPIO_FN_RAC_DSR, NULL);
+ gpio_request(GPIO_FN_RAC_DCD, NULL);
+ gpio_request(GPIO_FN_RAC_TXD, NULL);
+ gpio_request(GPIO_FN_COM1_TXD, NULL);
+ gpio_request(GPIO_FN_COM1_RXD, NULL);
+ gpio_request(GPIO_FN_COM1_RTS, NULL);
+ gpio_request(GPIO_FN_COM1_CTS, NULL);
+
+ writeb(0x10, 0xfe470000); /* SMR0: SerMux mode 0 */
+
+ /* IIC (PTM, PTR, PTS) */
+ gpio_request(GPIO_FN_SDA7, NULL);
+ gpio_request(GPIO_FN_SCL7, NULL);
+ gpio_request(GPIO_FN_SDA6, NULL);
+ gpio_request(GPIO_FN_SCL6, NULL);
+ gpio_request(GPIO_FN_SDA5, NULL);
+ gpio_request(GPIO_FN_SCL5, NULL);
+ gpio_request(GPIO_FN_SDA4, NULL);
+ gpio_request(GPIO_FN_SCL4, NULL);
+ gpio_request(GPIO_FN_SDA3, NULL);
+ gpio_request(GPIO_FN_SCL3, NULL);
+ gpio_request(GPIO_FN_SDA2, NULL);
+ gpio_request(GPIO_FN_SCL2, NULL);
+ gpio_request(GPIO_FN_SDA1, NULL);
+ gpio_request(GPIO_FN_SCL1, NULL);
+ gpio_request(GPIO_FN_SDA0, NULL);
+ gpio_request(GPIO_FN_SCL0, NULL);
+
+ /* USB (PTN) */
+ gpio_request(GPIO_FN_VBUS_EN, NULL);
+ gpio_request(GPIO_FN_VBUS_OC, NULL);
+
+ /* SGPIO1/0 (PTN, PTO) */
+ gpio_request(GPIO_FN_SGPIO1_CLK, NULL);
+ gpio_request(GPIO_FN_SGPIO1_LOAD, NULL);
+ gpio_request(GPIO_FN_SGPIO1_DI, NULL);
+ gpio_request(GPIO_FN_SGPIO1_DO, NULL);
+ gpio_request(GPIO_FN_SGPIO0_CLK, NULL);
+ gpio_request(GPIO_FN_SGPIO0_LOAD, NULL);
+ gpio_request(GPIO_FN_SGPIO0_DI, NULL);
+ gpio_request(GPIO_FN_SGPIO0_DO, NULL);
+
+ /* WDT (PTN) */
+ gpio_request(GPIO_FN_SUB_CLKIN, NULL);
+
+ /* System (PTT) */
+ gpio_request(GPIO_FN_STATUS1, NULL);
+ gpio_request(GPIO_FN_STATUS0, NULL);
+
+ /* PWMX (PTT) */
+ gpio_request(GPIO_FN_PWMX1, NULL);
+ gpio_request(GPIO_FN_PWMX0, NULL);
+
+ /* R-SPI (PTV) */
+ gpio_request(GPIO_FN_R_SPI_MOSI, NULL);
+ gpio_request(GPIO_FN_R_SPI_MISO, NULL);
+ gpio_request(GPIO_FN_R_SPI_RSPCK, NULL);
+ gpio_request(GPIO_FN_R_SPI_SSL0, NULL);
+ gpio_request(GPIO_FN_R_SPI_SSL1, NULL);
+
+ /* EVC (PTV, PTW) */
+ gpio_request(GPIO_FN_EVENT7, NULL);
+ gpio_request(GPIO_FN_EVENT6, NULL);
+ gpio_request(GPIO_FN_EVENT5, NULL);
+ gpio_request(GPIO_FN_EVENT4, NULL);
+ gpio_request(GPIO_FN_EVENT3, NULL);
+ gpio_request(GPIO_FN_EVENT2, NULL);
+ gpio_request(GPIO_FN_EVENT1, NULL);
+ gpio_request(GPIO_FN_EVENT0, NULL);
+
+ /* LED for heartbeat */
+ gpio_request(GPIO_PTU3, NULL);
+ gpio_direction_output(GPIO_PTU3, 1);
+ gpio_request(GPIO_PTU2, NULL);
+ gpio_direction_output(GPIO_PTU2, 1);
+ gpio_request(GPIO_PTU1, NULL);
+ gpio_direction_output(GPIO_PTU1, 1);
+ gpio_request(GPIO_PTU0, NULL);
+ gpio_direction_output(GPIO_PTU0, 1);
+
+ /* control for MDIO of Gigabit Ethernet */
+ gpio_request(GPIO_PTT4, NULL);
+ gpio_direction_output(GPIO_PTT4, 1);
+
+ /* control for eMMC */
+ gpio_request(GPIO_PTT7, NULL); /* eMMC_RST# */
+ gpio_direction_output(GPIO_PTT7, 0);
+ gpio_request(GPIO_PTT6, NULL); /* eMMC_INDEX# */
+ gpio_direction_output(GPIO_PTT6, 0);
+ gpio_request(GPIO_PTT5, NULL); /* eMMC_PRST# */
+ gpio_direction_output(GPIO_PTT5, 1);
+
+ /* General platform */
+ return platform_add_devices(sh7757lcr_devices,
+ ARRAY_SIZE(sh7757lcr_devices));
+}
+arch_initcall(sh7757lcr_devices_setup);
+
+/* Initialize IRQ setting */
+void __init init_sh7757lcr_IRQ(void)
+{
+ plat_irq_setup_pins(IRQ_MODE_IRQ7654);
+ plat_irq_setup_pins(IRQ_MODE_IRQ3210);
+}
+
+/* Initialize the board */
+static void __init sh7757lcr_setup(char **cmdline_p)
+{
+ printk(KERN_INFO "Renesas R0P7757LC0012RL support.\n");
+}
+
+static int sh7757lcr_mode_pins(void)
+{
+ int value = 0;
+
+ /* These are the factory default settings of S3 (Low active).
+ * If you change these dip switches then you will need to
+ * adjust the values below as well.
+ */
+ value |= MODE_PIN0; /* Clock Mode: 1 */
+
+ return value;
+}
+
+/* The Machine Vector */
+static struct sh_machine_vector mv_sh7757lcr __initmv = {
+ .mv_name = "SH7757LCR",
+ .mv_setup = sh7757lcr_setup,
+ .mv_init_irq = init_sh7757lcr_IRQ,
+ .mv_mode_pins = sh7757lcr_mode_pins,
+};
+
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 1d7b495a7db4..71a3368ab1fc 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -1248,14 +1248,14 @@ static int __init arch_setup(void)
/* set SPU2 clock to 83.4 MHz */
clk = clk_get(NULL, "spu_clk");
- if (clk) {
+ if (!IS_ERR(clk)) {
clk_set_rate(clk, clk_round_rate(clk, 83333333));
clk_put(clk);
}
/* change parent of FSI B */
clk = clk_get(NULL, "fsib_clk");
- if (clk) {
+ if (!IS_ERR(clk)) {
clk_register(&fsimckb_clk);
clk_set_parent(clk, &fsimckb_clk);
clk_set_rate(clk, 11000);
@@ -1273,7 +1273,7 @@ static int __init arch_setup(void)
/* set VPU clock to 166 MHz */
clk = clk_get(NULL, "vpu_clk");
- if (clk) {
+ if (!IS_ERR(clk)) {
clk_set_rate(clk, clk_round_rate(clk, 166000000));
clk_put(clk);
}
diff --git a/arch/sh/boards/mach-sdk7786/Makefile b/arch/sh/boards/mach-sdk7786/Makefile
index a29f19e85b63..23ff7d4ac491 100644
--- a/arch/sh/boards/mach-sdk7786/Makefile
+++ b/arch/sh/boards/mach-sdk7786/Makefile
@@ -1 +1,4 @@
-obj-y := setup.o fpga.o irq.o
+obj-y := fpga.o irq.o setup.o
+
+obj-$(CONFIG_GENERIC_GPIO) += gpio.o
+obj-$(CONFIG_HAVE_SRAM_POOL) += sram.o
diff --git a/arch/sh/boards/mach-sdk7786/gpio.c b/arch/sh/boards/mach-sdk7786/gpio.c
new file mode 100644
index 000000000000..f71ce09d4e15
--- /dev/null
+++ b/arch/sh/boards/mach-sdk7786/gpio.c
@@ -0,0 +1,49 @@
+/*
+ * SDK7786 FPGA USRGPIR Support.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <mach/fpga.h>
+
+#define NR_FPGA_GPIOS 8
+
+static const char *usrgpir_gpio_names[NR_FPGA_GPIOS] = {
+ "in0", "in1", "in2", "in3", "in4", "in5", "in6", "in7",
+};
+
+static int usrgpir_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ /* always in */
+ return 0;
+}
+
+static int usrgpir_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+ return !!(fpga_read_reg(USRGPIR) & (1 << gpio));
+}
+
+static struct gpio_chip usrgpir_gpio_chip = {
+ .label = "sdk7786-fpga",
+ .names = usrgpir_gpio_names,
+ .direction_input = usrgpir_gpio_direction_input,
+ .get = usrgpir_gpio_get,
+ .base = -1, /* don't care */
+ .ngpio = NR_FPGA_GPIOS,
+};
+
+static int __init usrgpir_gpio_setup(void)
+{
+ return gpiochip_add(&usrgpir_gpio_chip);
+}
+device_initcall(usrgpir_gpio_setup);
diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c
index 2ec1ea5cf8ef..7e0c4e3878e0 100644
--- a/arch/sh/boards/mach-sdk7786/setup.c
+++ b/arch/sh/boards/mach-sdk7786/setup.c
@@ -20,6 +20,8 @@
#include <asm/machvec.h>
#include <asm/heartbeat.h>
#include <asm/sizes.h>
+#include <asm/clock.h>
+#include <asm/clkdev.h>
#include <asm/reboot.h>
#include <asm/smp-ops.h>
@@ -140,6 +142,45 @@ static int sdk7786_mode_pins(void)
return fpga_read_reg(MODSWR);
}
+/*
+ * FPGA-driven PCIe clocks
+ *
+ * Historically these include the oscillator, clock B (slots 2/3/4) and
+ * clock A (slot 1 and the CPU clock). Newer revs of the PCB shove
+ * everything under a single PCIe clocks enable bit that happens to map
+ * to the same bit position as the oscillator bit for earlier FPGA
+ * versions.
+ *
+ * Given that the legacy clocks have the side-effect of shutting the CPU
+ * off through the FPGA along with the PCI slots, we simply leave them in
+ * their initial state and don't bother registering them with the clock
+ * framework.
+ */
+static int sdk7786_pcie_clk_enable(struct clk *clk)
+{
+ fpga_write_reg(fpga_read_reg(PCIECR) | PCIECR_CLKEN, PCIECR);
+ return 0;
+}
+
+static void sdk7786_pcie_clk_disable(struct clk *clk)
+{
+ fpga_write_reg(fpga_read_reg(PCIECR) & ~PCIECR_CLKEN, PCIECR);
+}
+
+static struct clk_ops sdk7786_pcie_clk_ops = {
+ .enable = sdk7786_pcie_clk_enable,
+ .disable = sdk7786_pcie_clk_disable,
+};
+
+static struct clk sdk7786_pcie_clk = {
+ .ops = &sdk7786_pcie_clk_ops,
+};
+
+static struct clk_lookup sdk7786_pcie_cl = {
+ .con_id = "pcie_plat_clk",
+ .clk = &sdk7786_pcie_clk,
+};
+
static int sdk7786_clk_init(void)
{
struct clk *clk;
@@ -158,7 +199,18 @@ static int sdk7786_clk_init(void)
ret = clk_set_rate(clk, 33333333);
clk_put(clk);
- return ret;
+ /*
+ * Setup the FPGA clocks.
+ */
+ ret = clk_register(&sdk7786_pcie_clk);
+ if (unlikely(ret)) {
+ pr_err("FPGA clock registration failed\n");
+ return ret;
+ }
+
+ clkdev_add(&sdk7786_pcie_cl);
+
+ return 0;
}
static void sdk7786_restart(char *cmd)
diff --git a/arch/sh/boards/mach-sdk7786/sram.c b/arch/sh/boards/mach-sdk7786/sram.c
new file mode 100644
index 000000000000..c81c3abbe01c
--- /dev/null
+++ b/arch/sh/boards/mach-sdk7786/sram.c
@@ -0,0 +1,72 @@
+/*
+ * SDK7786 FPGA SRAM Support.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <mach/fpga.h>
+#include <asm/sram.h>
+#include <asm/sizes.h>
+
+static int __init fpga_sram_init(void)
+{
+ unsigned long phys;
+ unsigned int area;
+ void __iomem *vaddr;
+ int ret;
+ u16 data;
+
+ /* Enable FPGA SRAM */
+ data = fpga_read_reg(LCLASR);
+ data |= LCLASR_FRAMEN;
+ fpga_write_reg(data, LCLASR);
+
+ /*
+ * FPGA_SEL determines the area mapping
+ */
+ area = (data & LCLASR_FPGA_SEL_MASK) >> LCLASR_FPGA_SEL_SHIFT;
+ if (unlikely(area == LCLASR_AREA_MASK)) {
+ pr_err("FPGA memory unmapped.\n");
+ return -ENXIO;
+ }
+
+ /*
+ * The memory itself occupies a 2KiB range at the top of the area
+ * immediately below the system registers.
+ */
+ phys = (area << 26) + SZ_64M - SZ_4K;
+
+ /*
+ * The FPGA SRAM resides in translatable physical space, so set
+ * up a mapping prior to inserting it in to the pool.
+ */
+ vaddr = ioremap(phys, SZ_2K);
+ if (unlikely(!vaddr)) {
+ pr_err("Failed remapping FPGA memory.\n");
+ return -ENXIO;
+ }
+
+ pr_info("Adding %dKiB of FPGA memory at 0x%08lx-0x%08lx "
+ "(area %d) to pool.\n",
+ SZ_2K >> 10, phys, phys + SZ_2K - 1, area);
+
+ ret = gen_pool_add(sram_pool, (unsigned long)vaddr, SZ_2K, -1);
+ if (unlikely(ret < 0)) {
+ pr_err("Failed adding memory\n");
+ iounmap(vaddr);
+ return ret;
+ }
+
+ return 0;
+}
+postcore_initcall(fpga_sram_init);
diff --git a/arch/sh/boards/mach-x3proto/Makefile b/arch/sh/boards/mach-x3proto/Makefile
index 983e4551fecf..708c21c919ff 100644
--- a/arch/sh/boards/mach-x3proto/Makefile
+++ b/arch/sh/boards/mach-x3proto/Makefile
@@ -1 +1,3 @@
obj-y += setup.o ilsel.o
+
+obj-$(CONFIG_GENERIC_GPIO) += gpio.o
diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c
new file mode 100644
index 000000000000..594adf76e46a
--- /dev/null
+++ b/arch/sh/boards/mach-x3proto/gpio.c
@@ -0,0 +1,135 @@
+/*
+ * arch/sh/boards/mach-x3proto/gpio.c
+ *
+ * Renesas SH-X3 Prototype Baseboard GPIO Support.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <mach/ilsel.h>
+#include <mach/hardware.h>
+
+#define KEYCTLR 0xb81c0000
+#define KEYOUTR 0xb81c0002
+#define KEYDETR 0xb81c0004
+
+static DEFINE_SPINLOCK(x3proto_gpio_lock);
+static unsigned int x3proto_gpio_irq_map[NR_BASEBOARD_GPIOS] = { 0, };
+
+static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ unsigned long flags;
+ unsigned int data;
+
+ spin_lock_irqsave(&x3proto_gpio_lock, flags);
+ data = __raw_readw(KEYCTLR);
+ data |= (1 << gpio);
+ __raw_writew(data, KEYCTLR);
+ spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
+
+ return 0;
+}
+
+static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+ return !!(__raw_readw(KEYDETR) & (1 << gpio));
+}
+
+static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+ return x3proto_gpio_irq_map[gpio];
+}
+
+static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
+ unsigned long mask;
+ int pin;
+
+ chip->mask_ack(irq);
+
+ mask = __raw_readw(KEYDETR);
+
+ for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
+ generic_handle_irq(x3proto_gpio_to_irq(NULL, pin));
+
+ chip->unmask(irq);
+}
+
+struct gpio_chip x3proto_gpio_chip = {
+ .label = "x3proto-gpio",
+ .direction_input = x3proto_gpio_direction_input,
+ .get = x3proto_gpio_get,
+ .to_irq = x3proto_gpio_to_irq,
+ .base = -1,
+ .ngpio = NR_BASEBOARD_GPIOS,
+};
+
+int __init x3proto_gpio_setup(void)
+{
+ int ilsel;
+ int ret, i;
+
+ ilsel = ilsel_enable(ILSEL_KEY);
+ if (unlikely(ilsel < 0))
+ return ilsel;
+
+ ret = gpiochip_add(&x3proto_gpio_chip);
+ if (unlikely(ret))
+ goto err_gpio;
+
+ for (i = 0; i < NR_BASEBOARD_GPIOS; i++) {
+ unsigned long flags;
+ int irq = create_irq();
+
+ if (unlikely(irq < 0)) {
+ ret = -EINVAL;
+ goto err_irq;
+ }
+
+ spin_lock_irqsave(&x3proto_gpio_lock, flags);
+ x3proto_gpio_irq_map[i] = irq;
+ set_irq_chip_and_handler_name(irq, &dummy_irq_chip,
+ handle_simple_irq, "gpio");
+ spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
+ }
+
+ pr_info("registering '%s' support, handling GPIOs %u -> %u, "
+ "bound to IRQ %u\n",
+ x3proto_gpio_chip.label, x3proto_gpio_chip.base,
+ x3proto_gpio_chip.base + x3proto_gpio_chip.ngpio,
+ ilsel);
+
+ set_irq_chained_handler(ilsel, x3proto_gpio_irq_handler);
+ set_irq_wake(ilsel, 1);
+
+ return 0;
+
+err_irq:
+ for (; i >= 0; --i)
+ if (x3proto_gpio_irq_map[i])
+ destroy_irq(x3proto_gpio_irq_map[i]);
+
+ ret = gpiochip_remove(&x3proto_gpio_chip);
+ if (unlikely(ret))
+ pr_err("Failed deregistering GPIO\n");
+
+err_gpio:
+ synchronize_irq(ilsel);
+
+ ilsel_disable(ILSEL_KEY);
+
+ return ret;
+}
diff --git a/arch/sh/boards/mach-x3proto/ilsel.c b/arch/sh/boards/mach-x3proto/ilsel.c
index 5c9842704c60..95e346139515 100644
--- a/arch/sh/boards/mach-x3proto/ilsel.c
+++ b/arch/sh/boards/mach-x3proto/ilsel.c
@@ -1,20 +1,22 @@
/*
- * arch/sh/boards/renesas/x3proto/ilsel.c
+ * arch/sh/boards/mach-x3proto/ilsel.c
*
* Helper routines for SH-X3 proto board ILSEL.
*
- * Copyright (C) 2007 Paul Mundt
+ * Copyright (C) 2007 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/bitmap.h>
#include <linux/io.h>
-#include <asm/ilsel.h>
+#include <mach/ilsel.h>
/*
* ILSEL is split across:
@@ -64,6 +66,8 @@ static void __ilsel_enable(ilsel_source_t set, unsigned int bit)
unsigned int tmp, shift;
unsigned long addr;
+ pr_notice("enabling ILSEL set %d\n", set);
+
addr = mk_ilsel_addr(bit);
shift = mk_ilsel_shift(bit);
@@ -92,8 +96,10 @@ int ilsel_enable(ilsel_source_t set)
{
unsigned int bit;
- /* Aliased sources must use ilsel_enable_fixed() */
- BUG_ON(set > ILSEL_KEY);
+ if (unlikely(set > ILSEL_KEY)) {
+ pr_err("Aliased sources must use ilsel_enable_fixed()\n");
+ return -EINVAL;
+ }
do {
bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS);
@@ -140,6 +146,8 @@ void ilsel_disable(unsigned int irq)
unsigned long addr;
unsigned int tmp;
+ pr_notice("disabling ILSEL set %d\n", irq);
+
addr = mk_ilsel_addr(irq);
tmp = __raw_readw(addr);
diff --git a/arch/sh/boards/mach-x3proto/setup.c b/arch/sh/boards/mach-x3proto/setup.c
index 102bf56befb4..d682e2b6a856 100644
--- a/arch/sh/boards/mach-x3proto/setup.c
+++ b/arch/sh/boards/mach-x3proto/setup.c
@@ -1,9 +1,9 @@
/*
- * arch/sh/boards/renesas/x3proto/setup.c
+ * arch/sh/boards/mach-x3proto/setup.c
*
* Renesas SH-X3 Prototype Board Support.
*
- * Copyright (C) 2007 - 2008 Paul Mundt
+ * Copyright (C) 2007 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -16,9 +16,13 @@
#include <linux/smc91x.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/input.h>
#include <linux/usb/r8a66597.h>
#include <linux/usb/m66592.h>
-#include <asm/ilsel.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <mach/ilsel.h>
+#include <mach/hardware.h>
#include <asm/smp-ops.h>
static struct resource heartbeat_resources[] = {
@@ -122,15 +126,128 @@ static struct platform_device m66592_usb_peripheral_device = {
.resource = m66592_usb_peripheral_resources,
};
+static struct gpio_keys_button baseboard_buttons[NR_BASEBOARD_GPIOS] = {
+ {
+ .desc = "key44",
+ .code = KEY_POWER,
+ .active_low = 1,
+ .wakeup = 1,
+ }, {
+ .desc = "key43",
+ .code = KEY_SUSPEND,
+ .active_low = 1,
+ .wakeup = 1,
+ }, {
+ .desc = "key42",
+ .code = KEY_KATAKANAHIRAGANA,
+ .active_low = 1,
+ }, {
+ .desc = "key41",
+ .code = KEY_SWITCHVIDEOMODE,
+ .active_low = 1,
+ }, {
+ .desc = "key34",
+ .code = KEY_F12,
+ .active_low = 1,
+ }, {
+ .desc = "key33",
+ .code = KEY_F11,
+ .active_low = 1,
+ }, {
+ .desc = "key32",
+ .code = KEY_F10,
+ .active_low = 1,
+ }, {
+ .desc = "key31",
+ .code = KEY_F9,
+ .active_low = 1,
+ }, {
+ .desc = "key24",
+ .code = KEY_F8,
+ .active_low = 1,
+ }, {
+ .desc = "key23",
+ .code = KEY_F7,
+ .active_low = 1,
+ }, {
+ .desc = "key22",
+ .code = KEY_F6,
+ .active_low = 1,
+ }, {
+ .desc = "key21",
+ .code = KEY_F5,
+ .active_low = 1,
+ }, {
+ .desc = "key14",
+ .code = KEY_F4,
+ .active_low = 1,
+ }, {
+ .desc = "key13",
+ .code = KEY_F3,
+ .active_low = 1,
+ }, {
+ .desc = "key12",
+ .code = KEY_F2,
+ .active_low = 1,
+ }, {
+ .desc = "key11",
+ .code = KEY_F1,
+ .active_low = 1,
+ },
+};
+
+static struct gpio_keys_platform_data baseboard_buttons_data = {
+ .buttons = baseboard_buttons,
+ .nbuttons = ARRAY_SIZE(baseboard_buttons),
+};
+
+static struct platform_device baseboard_buttons_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &baseboard_buttons_data,
+ },
+};
+
static struct platform_device *x3proto_devices[] __initdata = {
&heartbeat_device,
&smc91x_device,
&r8a66597_usb_host_device,
&m66592_usb_peripheral_device,
+ &baseboard_buttons_device,
};
+static void __init x3proto_init_irq(void)
+{
+ plat_irq_setup_pins(IRQ_MODE_IRL3210);
+
+ /* Set ICR0.LVLMODE */
+ __raw_writel(__raw_readl(0xfe410000) | (1 << 21), 0xfe410000);
+}
+
static int __init x3proto_devices_setup(void)
{
+ int ret, i;
+
+ /*
+ * IRLs are only needed for ILSEL mappings, so flip over the INTC
+ * pins at a later point to enable the GPIOs to settle.
+ */
+ x3proto_init_irq();
+
+ /*
+ * Now that ILSELs are available, set up the baseboard GPIOs.
+ */
+ ret = x3proto_gpio_setup();
+ if (unlikely(ret))
+ return ret;
+
+ /*
+ * Propagate dynamic GPIOs for the baseboard button device.
+ */
+ for (i = 0; i < ARRAY_SIZE(baseboard_buttons); i++)
+ baseboard_buttons[i].gpio = x3proto_gpio_chip.base + i;
+
r8a66597_usb_host_resources[1].start =
r8a66597_usb_host_resources[1].end = ilsel_enable(ILSEL_USBH_I);
@@ -145,14 +262,6 @@ static int __init x3proto_devices_setup(void)
}
device_initcall(x3proto_devices_setup);
-static void __init x3proto_init_irq(void)
-{
- plat_irq_setup_pins(IRQ_MODE_IRL3210);
-
- /* Set ICR0.LVLMODE */
- __raw_writel(__raw_readl(0xfe410000) | (1 << 21), 0xfe410000);
-}
-
static void __init x3proto_setup(char **cmdline_p)
{
register_smp_ops(&shx3_smp_ops);
@@ -161,5 +270,4 @@ static void __init x3proto_setup(char **cmdline_p)
static struct sh_machine_vector mv_x3proto __initmv = {
.mv_name = "x3proto",
.mv_setup = x3proto_setup,
- .mv_init_irq = x3proto_init_irq,
};
diff --git a/arch/sh/boot/compressed/head_32.S b/arch/sh/boot/compressed/head_32.S
index 200c1d4f1efe..3e150326f1fd 100644
--- a/arch/sh/boot/compressed/head_32.S
+++ b/arch/sh/boot/compressed/head_32.S
@@ -91,7 +91,9 @@ bss_start_addr:
end_addr:
.long _end
init_sr:
- .long 0x400000F0 /* Privileged mode, Bank=0, Block=0, IMASK=0xF */
+ .long 0x500000F0 /* Privileged mode, Bank=0, Block=1, IMASK=0xF */
+kexec_magic:
+ .long 0x400000F0 /* magic used by kexec to parse zImage format */
init_stack_addr:
.long stack_start
decompress_kernel_addr:
diff --git a/arch/sh/cchips/hd6446x/Makefile b/arch/sh/cchips/hd6446x/Makefile
index 9682e3ab668f..59c348337bb8 100644
--- a/arch/sh/cchips/hd6446x/Makefile
+++ b/arch/sh/cchips/hd6446x/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_HD64461) += hd64461.o
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff --git a/arch/sh/configs/ap325rxa_defconfig b/arch/sh/configs/ap325rxa_defconfig
index 238d6833ac70..e5335123b5e9 100644
--- a/arch/sh/configs/ap325rxa_defconfig
+++ b/arch/sh/configs/ap325rxa_defconfig
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/cayman_defconfig b/arch/sh/configs/cayman_defconfig
index b3bf11bcf025..67e150631ea5 100644
--- a/arch/sh/configs/cayman_defconfig
+++ b/arch/sh/configs/cayman_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/dreamcast_defconfig b/arch/sh/configs/dreamcast_defconfig
index 3cdee4f0c184..ec243ca29529 100644
--- a/arch/sh/configs/dreamcast_defconfig
+++ b/arch/sh/configs/dreamcast_defconfig
@@ -2,7 +2,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
diff --git a/arch/sh/configs/ecovec24-romimage_defconfig b/arch/sh/configs/ecovec24-romimage_defconfig
index 021633b02835..5fcb17bff24a 100644
--- a/arch/sh/configs/ecovec24-romimage_defconfig
+++ b/arch/sh/configs/ecovec24-romimage_defconfig
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/edosk7760_defconfig b/arch/sh/configs/edosk7760_defconfig
index 365f2318e9b5..e1077a041ac3 100644
--- a/arch/sh/configs/edosk7760_defconfig
+++ b/arch/sh/configs/edosk7760_defconfig
@@ -5,7 +5,6 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_KALLSYMS_ALL=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/espt_defconfig b/arch/sh/configs/espt_defconfig
index ca7fc1b3d567..67cb1094a033 100644
--- a/arch/sh/configs/espt_defconfig
+++ b/arch/sh/configs/espt_defconfig
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
diff --git a/arch/sh/configs/hp6xx_defconfig b/arch/sh/configs/hp6xx_defconfig
index 45c18a3830d2..496edcdf95a3 100644
--- a/arch/sh/configs/hp6xx_defconfig
+++ b/arch/sh/configs/hp6xx_defconfig
@@ -3,7 +3,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/kfr2r09-romimage_defconfig b/arch/sh/configs/kfr2r09-romimage_defconfig
index d4268b1953bc..029a506ca325 100644
--- a/arch/sh/configs/kfr2r09-romimage_defconfig
+++ b/arch/sh/configs/kfr2r09-romimage_defconfig
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/kfr2r09_defconfig b/arch/sh/configs/kfr2r09_defconfig
index ad5d296b375f..fac13ded07b2 100644
--- a/arch/sh/configs/kfr2r09_defconfig
+++ b/arch/sh/configs/kfr2r09_defconfig
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/landisk_defconfig b/arch/sh/configs/landisk_defconfig
index 14e658e9318f..3670e937f2b7 100644
--- a/arch/sh/configs/landisk_defconfig
+++ b/arch/sh/configs/landisk_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_SLAB=y
diff --git a/arch/sh/configs/lboxre2_defconfig b/arch/sh/configs/lboxre2_defconfig
index 6be7eaaa8bb6..e3c0894b1bb4 100644
--- a/arch/sh/configs/lboxre2_defconfig
+++ b/arch/sh/configs/lboxre2_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_SLAB=y
diff --git a/arch/sh/configs/magicpanelr2_defconfig b/arch/sh/configs/magicpanelr2_defconfig
index 4d61b7711b40..9479872b1ae6 100644
--- a/arch/sh/configs/magicpanelr2_defconfig
+++ b/arch/sh/configs/magicpanelr2_defconfig
@@ -5,7 +5,6 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_AUDIT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
diff --git a/arch/sh/configs/microdev_defconfig b/arch/sh/configs/microdev_defconfig
index 0e32a24fed53..f1d2e1b5ee41 100644
--- a/arch/sh/configs/microdev_defconfig
+++ b/arch/sh/configs/microdev_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
diff --git a/arch/sh/configs/migor_defconfig b/arch/sh/configs/migor_defconfig
index c19fcdfdee37..9ad904a110de 100644
--- a/arch/sh/configs/migor_defconfig
+++ b/arch/sh/configs/migor_defconfig
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
diff --git a/arch/sh/configs/polaris_defconfig b/arch/sh/configs/polaris_defconfig
index 984e3fe1ce5d..f3d5d9f76310 100644
--- a/arch/sh/configs/polaris_defconfig
+++ b/arch/sh/configs/polaris_defconfig
@@ -7,7 +7,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_AUDIT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/r7780mp_defconfig b/arch/sh/configs/r7780mp_defconfig
index e8b5472e6d84..920b8471ceb7 100644
--- a/arch/sh/configs/r7780mp_defconfig
+++ b/arch/sh/configs/r7780mp_defconfig
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/sh/configs/r7785rp_defconfig b/arch/sh/configs/r7785rp_defconfig
index fd8848060982..c77da6be06b8 100644
--- a/arch/sh/configs/r7785rp_defconfig
+++ b/arch/sh/configs/r7785rp_defconfig
@@ -8,7 +8,6 @@ CONFIG_RCU_TRACE=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
diff --git a/arch/sh/configs/rts7751r2d1_defconfig b/arch/sh/configs/rts7751r2d1_defconfig
index a42f7c22ca1a..a3d081095ce2 100644
--- a/arch/sh/configs/rts7751r2d1_defconfig
+++ b/arch/sh/configs/rts7751r2d1_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/rts7751r2dplus_defconfig b/arch/sh/configs/rts7751r2dplus_defconfig
index 742aa61f2427..b1a04f3c598b 100644
--- a/arch/sh/configs/rts7751r2dplus_defconfig
+++ b/arch/sh/configs/rts7751r2dplus_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/sdk7780_defconfig b/arch/sh/configs/sdk7780_defconfig
index aed394d89346..ae1115849dda 100644
--- a/arch/sh/configs/sdk7780_defconfig
+++ b/arch/sh/configs/sdk7780_defconfig
@@ -6,7 +6,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=18
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
CONFIG_KALLSYMS_ALL=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/se7343_defconfig b/arch/sh/configs/se7343_defconfig
index 7a7e13853cfd..be9c474197b3 100644
--- a/arch/sh/configs/se7343_defconfig
+++ b/arch/sh/configs/se7343_defconfig
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/sh/configs/se7712_defconfig b/arch/sh/configs/se7712_defconfig
index 3620a7f4c821..1248635e4f88 100644
--- a/arch/sh/configs/se7712_defconfig
+++ b/arch/sh/configs/se7712_defconfig
@@ -5,7 +5,6 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_KALLSYMS_ALL=y
# CONFIG_BUG is not set
diff --git a/arch/sh/configs/se7721_defconfig b/arch/sh/configs/se7721_defconfig
index fe22f599c0cb..c3ba6e8a9818 100644
--- a/arch/sh/configs/se7721_defconfig
+++ b/arch/sh/configs/se7721_defconfig
@@ -5,7 +5,6 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_KALLSYMS_ALL=y
# CONFIG_BUG is not set
diff --git a/arch/sh/configs/se7722_defconfig b/arch/sh/configs/se7722_defconfig
index b9b64c38810e..ae998c7e2ee0 100644
--- a/arch/sh/configs/se7722_defconfig
+++ b/arch/sh/configs/se7722_defconfig
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/se7724_defconfig b/arch/sh/configs/se7724_defconfig
index 03e736781c2e..ed35093e3758 100644
--- a/arch/sh/configs/se7724_defconfig
+++ b/arch/sh/configs/se7724_defconfig
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/se7750_defconfig b/arch/sh/configs/se7750_defconfig
index 1a686b6d5cd4..912c98590e22 100644
--- a/arch/sh/configs/se7750_defconfig
+++ b/arch/sh/configs/se7750_defconfig
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_HOTPLUG is not set
diff --git a/arch/sh/configs/se7751_defconfig b/arch/sh/configs/se7751_defconfig
index 7e03451a9fad..75c92fc1876b 100644
--- a/arch/sh/configs/se7751_defconfig
+++ b/arch/sh/configs/se7751_defconfig
@@ -2,7 +2,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
diff --git a/arch/sh/configs/se7780_defconfig b/arch/sh/configs/se7780_defconfig
index 4cfc4deff135..c8c5e7f7a68d 100644
--- a/arch/sh/configs/se7780_defconfig
+++ b/arch/sh/configs/se7780_defconfig
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_EPOLL is not set
diff --git a/arch/sh/configs/sh03_defconfig b/arch/sh/configs/sh03_defconfig
index b95dc76b04c1..2051821724c6 100644
--- a/arch/sh/configs/sh03_defconfig
+++ b/arch/sh/configs/sh03_defconfig
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/sh2007_defconfig b/arch/sh/configs/sh2007_defconfig
new file mode 100644
index 000000000000..0d2f41472a19
--- /dev/null
+++ b/arch/sh/configs/sh2007_defconfig
@@ -0,0 +1,212 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_IKCONFIG=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7780=y
+CONFIG_MEMORY_SIZE=0x08000000
+# CONFIG_VSYSCALL is not set
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SH2007=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SH_DMA=y
+CONFIG_SH_DMA_API=y
+CONFIG_NR_DMA_CHANNELS_BOOL=y
+CONFIG_HZ_100=y
+CONFIG_CMDLINE_OVERWRITE=y
+CONFIG_CMDLINE="console=ttySC1,115200 ip=dhcp root=/dev/nfs rw nfsroot=/nfs/rootfs,rsize=1024,wsize=1024 earlyprintk=sh-sci.1"
+CONFIG_PCCARD=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_NET_IPIP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NET_PKTGEN=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_CDROM_PKTCDVD=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_RAID_ATTRS=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_SCSI_SRP_ATTRS=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_EQUALIZER=y
+CONFIG_TUN=y
+CONFIG_VETH=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMSC911X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_INPUT_FF_MEMLESS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_SH_WDT=y
+CONFIG_SSB=y
+CONFIG_FB=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_MON=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_DMADEVICES=y
+CONFIG_TIMB_DMA=y
+CONFIG_EXT3_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=932
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_UTF8=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SH_STANDARD_BIOS=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=y
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_XTS=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_TGR192=y
+CONFIG_CRYPTO_WP512=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=y
+CONFIG_CRYPTO_CAMELLIA=y
+CONFIG_CRYPTO_CAST5=y
+CONFIG_CRYPTO_CAST6=y
+CONFIG_CRYPTO_FCRYPT=y
+CONFIG_CRYPTO_KHAZAD=y
+CONFIG_CRYPTO_SEED=y
+CONFIG_CRYPTO_SERPENT=y
+CONFIG_CRYPTO_TEA=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/sh/configs/sh7710voipgw_defconfig b/arch/sh/configs/sh7710voipgw_defconfig
index b804641c8dd2..f92ad17cd629 100644
--- a/arch/sh/configs/sh7710voipgw_defconfig
+++ b/arch/sh/configs/sh7710voipgw_defconfig
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/sh/configs/sh7757lcr_defconfig b/arch/sh/configs/sh7757lcr_defconfig
new file mode 100644
index 000000000000..273f3fa198f7
--- /dev/null
+++ b/arch/sh/configs/sh7757lcr_defconfig
@@ -0,0 +1,85 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7757=y
+CONFIG_MEMORY_START=0x40000000
+CONFIG_MEMORY_SIZE=0x0f000000
+CONFIG_PMB=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SH7757LCR=y
+CONFIG_HEARTBEAT=y
+CONFIG_SECCOMP=y
+CONFIG_CMDLINE_OVERWRITE=y
+CONFIG_CMDLINE="console=ttySC2,115200 root=/dev/nfs ip=dhcp"
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_PHYLIB=y
+CONFIG_VITESSE_PHY=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_INOTIFY=y
+CONFIG_ISO9660_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_SQUASHFS=y
+CONFIG_MINIX_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_FTRACE is not set
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/sh/configs/sh7763rdp_defconfig b/arch/sh/configs/sh7763rdp_defconfig
index 361876786932..479536440264 100644
--- a/arch/sh/configs/sh7763rdp_defconfig
+++ b/arch/sh/configs/sh7763rdp_defconfig
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
diff --git a/arch/sh/configs/sh7785lcr_defconfig b/arch/sh/configs/sh7785lcr_defconfig
index ee6b81f7539e..51561f5677d8 100644
--- a/arch/sh/configs/sh7785lcr_defconfig
+++ b/arch/sh/configs/sh7785lcr_defconfig
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/shx3_defconfig b/arch/sh/configs/shx3_defconfig
index bb4f60c0f866..3f92d37c6374 100644
--- a/arch/sh/configs/shx3_defconfig
+++ b/arch/sh/configs/shx3_defconfig
@@ -15,7 +15,6 @@ CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_MEM_RES_CTLR=y
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
diff --git a/arch/sh/configs/snapgear_defconfig b/arch/sh/configs/snapgear_defconfig
index f38c98341f15..7eae4e59d7f0 100644
--- a/arch/sh/configs/snapgear_defconfig
+++ b/arch/sh/configs/snapgear_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_HOTPLUG is not set
diff --git a/arch/sh/configs/systemh_defconfig b/arch/sh/configs/systemh_defconfig
index 7007d00c67e0..b58dfc505efe 100644
--- a/arch/sh/configs/systemh_defconfig
+++ b/arch/sh/configs/systemh_defconfig
@@ -1,6 +1,5 @@
CONFIG_EXPERIMENTAL=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
diff --git a/arch/sh/configs/titan_defconfig b/arch/sh/configs/titan_defconfig
index 45c309ff447e..0f558914e760 100644
--- a/arch/sh/configs/titan_defconfig
+++ b/arch/sh/configs/titan_defconfig
@@ -5,7 +5,6 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
diff --git a/arch/sh/configs/ul2_defconfig b/arch/sh/configs/ul2_defconfig
index e107d424acf0..2d288b887fbd 100644
--- a/arch/sh/configs/ul2_defconfig
+++ b/arch/sh/configs/ul2_defconfig
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c
index 4a277224a871..f46848f088e4 100644
--- a/arch/sh/drivers/dma/dma-api.c
+++ b/arch/sh/drivers/dma/dma-api.c
@@ -412,8 +412,8 @@ EXPORT_SYMBOL(unregister_dmac);
static int __init dma_api_init(void)
{
printk(KERN_NOTICE "DMA: Registering DMA API.\n");
- create_proc_read_entry("dma", 0, 0, dma_read_proc, 0);
- return 0;
+ return create_proc_read_entry("dma", 0, 0, dma_read_proc, 0)
+ ? 0 : -ENOMEM;
}
subsys_initcall(dma_api_init);
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index 4a59e6890876..82f0a335fd19 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_SH_RTS7751R2D) += fixups-rts7751r2d.o
obj-$(CONFIG_SH_SH03) += fixups-sh03.o
obj-$(CONFIG_SH_HIGHLANDER) += fixups-r7780rp.o
obj-$(CONFIG_SH_SH7785LCR) += fixups-r7780rp.o
+obj-$(CONFIG_SH_SDK7786) += fixups-sdk7786.o
obj-$(CONFIG_SH_SDK7780) += fixups-sdk7780.o
obj-$(CONFIG_SH_7780_SOLUTION_ENGINE) += fixups-sdk7780.o
obj-$(CONFIG_SH_TITAN) += fixups-titan.o
diff --git a/arch/sh/drivers/pci/fixups-sdk7786.c b/arch/sh/drivers/pci/fixups-sdk7786.c
new file mode 100644
index 000000000000..0e18ee332553
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-sdk7786.c
@@ -0,0 +1,67 @@
+/*
+ * SDK7786 FPGA PCIe mux handling
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "PCI: " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <mach/fpga.h>
+
+/*
+ * The SDK7786 FPGA supports mangling of most of the slots in some way or
+ * another. Slots 3/4 are special in that only one can be supported at a
+ * time, and both appear on port 3 to the PCI bus scan. Enabling slot 4
+ * (the horizontal edge connector) will disable slot 3 entirely.
+ *
+ * Misconfigurations can be detected through the FPGA via the slot
+ * resistors to determine card presence. Hotplug remains unsupported.
+ */
+static unsigned int slot4en __devinitdata;
+
+char *__devinit pcibios_setup(char *str)
+{
+ if (strcmp(str, "slot4en") == 0) {
+ slot4en = 1;
+ return NULL;
+ }
+
+ return str;
+}
+
+static int __init sdk7786_pci_init(void)
+{
+ u16 data = fpga_read_reg(PCIECR);
+
+ /*
+ * Enable slot #4 if it's been specified on the command line.
+ *
+ * Optionally reroute if slot #4 has a card present while slot #3
+ * does not, regardless of command line value.
+ *
+ * Card presence is logically inverted.
+ */
+ slot4en ?: (!(data & PCIECR_PRST4) && (data & PCIECR_PRST3));
+ if (slot4en) {
+ pr_info("Activating PCIe slot#4 (disabling slot#3)\n");
+
+ data &= ~PCIECR_PCIEMUX1;
+ fpga_write_reg(data, PCIECR);
+
+ /* Warn about forced rerouting if slot#3 is occupied */
+ if ((data & PCIECR_PRST3) == 0) {
+ pr_warning("Unreachable card detected in slot#3\n");
+ return -EBUSY;
+ }
+ } else
+ pr_info("PCIe slot#4 disabled\n");
+
+ return 0;
+}
+postcore_initcall(sdk7786_pci_init);
diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c
index 0b81999fb88b..b6234203e0ac 100644
--- a/arch/sh/drivers/pci/ops-sh4.c
+++ b/arch/sh/drivers/pci/ops-sh4.c
@@ -9,6 +9,7 @@
*/
#include <linux/pci.h>
#include <linux/io.h>
+#include <linux/spinlock.h>
#include <asm/addrspace.h>
#include "pci-sh4.h"
@@ -18,8 +19,6 @@
#define CONFIG_CMD(bus, devfn, where) \
(0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
-static DEFINE_SPINLOCK(sh4_pci_lock);
-
/*
* Functions for accessing PCI configuration space with type 1 accesses
*/
@@ -34,10 +33,10 @@ static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn,
* PCIPDR may only be accessed as 32 bit words,
* so we must do byte alignment by hand
*/
- spin_lock_irqsave(&sh4_pci_lock, flags);
+ raw_spin_lock_irqsave(&pci_config_lock, flags);
pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
data = pci_read_reg(chan, SH4_PCIPDR);
- spin_unlock_irqrestore(&sh4_pci_lock, flags);
+ raw_spin_unlock_irqrestore(&pci_config_lock, flags);
switch (size) {
case 1:
@@ -69,10 +68,10 @@ static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn,
int shift;
u32 data;
- spin_lock_irqsave(&sh4_pci_lock, flags);
+ raw_spin_lock_irqsave(&pci_config_lock, flags);
pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
data = pci_read_reg(chan, SH4_PCIPDR);
- spin_unlock_irqrestore(&sh4_pci_lock, flags);
+ raw_spin_unlock_irqrestore(&pci_config_lock, flags);
switch (size) {
case 1:
diff --git a/arch/sh/drivers/pci/ops-sh7786.c b/arch/sh/drivers/pci/ops-sh7786.c
index 48f594b9582b..128421009e3f 100644
--- a/arch/sh/drivers/pci/ops-sh7786.c
+++ b/arch/sh/drivers/pci/ops-sh7786.c
@@ -1,7 +1,7 @@
/*
* Generic SH7786 PCI-Express operations.
*
- * Copyright (C) 2009 Paul Mundt
+ * Copyright (C) 2009 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file "COPYING" in the main directory of this archive
@@ -19,37 +19,72 @@ enum {
PCI_ACCESS_WRITE,
};
-static DEFINE_SPINLOCK(sh7786_pcie_lock);
-
static int sh7786_pcie_config_access(unsigned char access_type,
struct pci_bus *bus, unsigned int devfn, int where, u32 *data)
{
struct pci_channel *chan = bus->sysdata;
- int dev, func;
+ int dev, func, type, reg;
dev = PCI_SLOT(devfn);
func = PCI_FUNC(devfn);
+ type = !!bus->parent;
+ reg = where & ~3;
if (bus->number > 255 || dev > 31 || func > 7)
return PCIBIOS_FUNC_NOT_SUPPORTED;
- if (devfn)
- return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * While each channel has its own memory-mapped extended config
+ * space, it's generally only accessible when in endpoint mode.
+ * When in root complex mode, the controller is unable to target
+ * itself with either type 0 or type 1 accesses, and indeed, any
+ * controller initiated target transfer to its own config space
+ * result in a completer abort.
+ *
+ * Each channel effectively only supports a single device, but as
+ * the same channel <-> device access works for any PCI_SLOT()
+ * value, we cheat a bit here and bind the controller's config
+ * space to devfn 0 in order to enable self-enumeration. In this
+ * case the regular PAR/PDR path is sidelined and the mangled
+ * config access itself is initiated as a SuperHyway transaction.
+ */
+ if (pci_is_root_bus(bus)) {
+ if (dev == 0) {
+ if (access_type == PCI_ACCESS_READ)
+ *data = pci_read_reg(chan, PCI_REG(reg));
+ else
+ pci_write_reg(chan, *data, PCI_REG(reg));
+
+ return PCIBIOS_SUCCESSFUL;
+ } else if (dev > 1)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ /* Clear errors */
+ pci_write_reg(chan, pci_read_reg(chan, SH4A_PCIEERRFR), SH4A_PCIEERRFR);
/* Set the PIO address */
pci_write_reg(chan, (bus->number << 24) | (dev << 19) |
- (func << 16) | (where & ~3), SH4A_PCIEPAR);
+ (func << 16) | reg, SH4A_PCIEPAR);
/* Enable the configuration access */
- pci_write_reg(chan, (1 << 31), SH4A_PCIEPCTLR);
+ pci_write_reg(chan, (1 << 31) | (type << 8), SH4A_PCIEPCTLR);
+
+ /* Check for errors */
+ if (pci_read_reg(chan, SH4A_PCIEERRFR) & 0x10)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /* Check for master and target aborts */
+ if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
if (access_type == PCI_ACCESS_READ)
*data = pci_read_reg(chan, SH4A_PCIEPDR);
else
pci_write_reg(chan, *data, SH4A_PCIEPDR);
- /* Check for master and target aborts */
- if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
- return PCIBIOS_DEVICE_NOT_FOUND;
+ /* Disable the configuration access */
+ pci_write_reg(chan, 0, SH4A_PCIEPCTLR);
return PCIBIOS_SUCCESSFUL;
}
@@ -66,11 +101,13 @@ static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn,
else if ((size == 4) && (where & 3))
return PCIBIOS_BAD_REGISTER_NUMBER;
- spin_lock_irqsave(&sh7786_pcie_lock, flags);
+ raw_spin_lock_irqsave(&pci_config_lock, flags);
ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
devfn, where, &data);
- if (ret != PCIBIOS_SUCCESSFUL)
+ if (ret != PCIBIOS_SUCCESSFUL) {
+ *val = 0xffffffff;
goto out;
+ }
if (size == 1)
*val = (data >> ((where & 3) << 3)) & 0xff;
@@ -84,7 +121,7 @@ static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn,
devfn, where, size, (unsigned long)*val);
out:
- spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
+ raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return ret;
}
@@ -100,7 +137,7 @@ static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn,
else if ((size == 4) && (where & 3))
return PCIBIOS_BAD_REGISTER_NUMBER;
- spin_lock_irqsave(&sh7786_pcie_lock, flags);
+ raw_spin_lock_irqsave(&pci_config_lock, flags);
ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
devfn, where, &data);
if (ret != PCIBIOS_SUCCESSFUL)
@@ -124,7 +161,7 @@ static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn,
ret = sh7786_pcie_config_access(PCI_ACCESS_WRITE, bus,
devfn, where, &data);
out:
- spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
+ raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return ret;
}
diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c
index f98141b3b7d7..86adb1e235cd 100644
--- a/arch/sh/drivers/pci/pci-sh7751.c
+++ b/arch/sh/drivers/pci/pci-sh7751.c
@@ -81,7 +81,7 @@ static int __init sh7751_pci_init(void)
unsigned int id;
u32 word, reg;
- printk(KERN_NOTICE "PCI: Starting intialization.\n");
+ printk(KERN_NOTICE "PCI: Starting initialization.\n");
chan->reg_base = 0xfe200000;
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index ffdcbf10b95e..edb7cca14882 100644
--- a/arch/sh/drivers/pci/pci-sh7780.c
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -246,7 +246,7 @@ static int __init sh7780_pci_init(void)
const char *type;
int ret, i;
- printk(KERN_NOTICE "PCI: Starting intialization.\n");
+ printk(KERN_NOTICE "PCI: Starting initialization.\n");
chan->reg_base = 0xfe040000;
diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h
index 205dcbefe275..1742e2c9db7a 100644
--- a/arch/sh/drivers/pci/pci-sh7780.h
+++ b/arch/sh/drivers/pci/pci-sh7780.h
@@ -12,12 +12,6 @@
#ifndef _PCI_SH7780_H_
#define _PCI_SH7780_H_
-#define PCI_VENDOR_ID_RENESAS 0x1912
-#define PCI_DEVICE_ID_RENESAS_SH7781 0x0001
-#define PCI_DEVICE_ID_RENESAS_SH7780 0x0002
-#define PCI_DEVICE_ID_RENESAS_SH7763 0x0004
-#define PCI_DEVICE_ID_RENESAS_SH7785 0x0007
-
/* SH7780 Control Registers */
#define PCIECR 0xFE000008
#define PCIECR_ENBL 0x01
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 1e9598d2bbf4..60ee09a4e121 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -19,6 +19,7 @@
#include <linux/dma-debug.h>
#include <linux/io.h>
#include <linux/mutex.h>
+#include <linux/spinlock.h>
unsigned long PCIBIOS_MIN_IO = 0x0000;
unsigned long PCIBIOS_MIN_MEM = 0;
@@ -56,6 +57,11 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose)
}
}
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+DEFINE_RAW_SPINLOCK(pci_config_lock);
static DEFINE_MUTEX(pci_scan_mutex);
int __devinit register_pci_controller(struct pci_channel *hose)
@@ -233,40 +239,7 @@ void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
- u16 cmd, old_cmd;
- int idx;
- struct resource *r;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- old_cmd = cmd;
- for (idx=0; idx < PCI_NUM_RESOURCES; idx++) {
- /* Only set up the requested stuff */
- if (!(mask & (1<<idx)))
- continue;
-
- r = &dev->resource[idx];
- if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
- continue;
- if ((idx == PCI_ROM_RESOURCE) &&
- (!(r->flags & IORESOURCE_ROM_ENABLE)))
- continue;
- if (!r->start && r->end) {
- printk(KERN_ERR "PCI: Device %s not available "
- "because of resource collisions\n",
- pci_name(dev));
- return -EINVAL;
- }
- if (r->flags & IORESOURCE_IO)
- cmd |= PCI_COMMAND_IO;
- if (r->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
- }
- if (cmd != old_cmd) {
- printk("PCI: Enabling device %s (%04x -> %04x)\n",
- pci_name(dev), old_cmd, cmd);
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
- return 0;
+ return pci_enable_resources(dev, mask);
}
/*
@@ -295,7 +268,7 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
-char * __devinit pcibios_setup(char *str)
+char * __devinit __weak pcibios_setup(char *str)
{
return str;
}
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index 68cb9b0ac9d2..96e9b058aa1d 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -13,11 +13,14 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/sh_clk.h>
#include "pcie-sh7786.h"
#include <asm/sizes.h>
struct sh7786_pcie_port {
struct pci_channel *hose;
+ struct clk *fclk, phy_clk;
unsigned int index;
int endpoint;
int link;
@@ -51,6 +54,7 @@ static struct resource sh7786_pci0_resources[] = {
.name = "PCIe0 MEM 2",
.start = 0xfe100000,
.end = 0xfe100000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
},
};
@@ -74,6 +78,7 @@ static struct resource sh7786_pci1_resources[] = {
.name = "PCIe1 MEM 2",
.start = 0xfe300000,
.end = 0xfe300000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
},
};
@@ -82,6 +87,7 @@ static struct resource sh7786_pci2_resources[] = {
.name = "PCIe2 IO",
.start = 0xfc800000,
.end = 0xfc800000 + SZ_4M - 1,
+ .flags = IORESOURCE_IO,
}, {
.name = "PCIe2 MEM 0",
.start = 0x80000000,
@@ -96,6 +102,7 @@ static struct resource sh7786_pci2_resources[] = {
.name = "PCIe2 MEM 2",
.start = 0xfcd00000,
.end = 0xfcd00000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
},
};
@@ -117,7 +124,29 @@ static struct pci_channel sh7786_pci_channels[] = {
DEFINE_CONTROLLER(0xfcc00000, 2),
};
-static int phy_wait_for_ack(struct pci_channel *chan)
+static struct clk fixed_pciexclkp = {
+ .rate = 100000000, /* 100 MHz reference clock */
+};
+
+static void __devinit sh7786_pci_fixup(struct pci_dev *dev)
+{
+ /*
+ * Prevent enumeration of root complex resources.
+ */
+ if (pci_is_root_bus(dev->bus) && dev->devfn == 0) {
+ int i;
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ dev->resource[i].start = 0;
+ dev->resource[i].end = 0;
+ dev->resource[i].flags = 0;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_SH7786,
+ sh7786_pci_fixup);
+
+static int __init phy_wait_for_ack(struct pci_channel *chan)
{
unsigned int timeout = 100;
@@ -131,7 +160,7 @@ static int phy_wait_for_ack(struct pci_channel *chan)
return -ETIMEDOUT;
}
-static int pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
+static int __init pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
{
unsigned int timeout = 100;
@@ -145,19 +174,14 @@ static int pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
return -ETIMEDOUT;
}
-static void phy_write_reg(struct pci_channel *chan, unsigned int addr,
- unsigned int lane, unsigned int data)
+static void __init phy_write_reg(struct pci_channel *chan, unsigned int addr,
+ unsigned int lane, unsigned int data)
{
- unsigned long phyaddr, ctrl;
+ unsigned long phyaddr;
phyaddr = (1 << BITS_CMD) + ((lane & 0xf) << BITS_LANE) +
((addr & 0xff) << BITS_ADR);
- /* Enable clock */
- ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
- ctrl |= (1 << BITS_CKE);
- pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
-
/* Set write data */
pci_write_reg(chan, data, SH4A_PCIEPHYDOUTR);
pci_write_reg(chan, phyaddr, SH4A_PCIEPHYADRR);
@@ -165,20 +189,74 @@ static void phy_write_reg(struct pci_channel *chan, unsigned int addr,
phy_wait_for_ack(chan);
/* Clear command */
+ pci_write_reg(chan, 0, SH4A_PCIEPHYDOUTR);
pci_write_reg(chan, 0, SH4A_PCIEPHYADRR);
phy_wait_for_ack(chan);
+}
- /* Disable clock */
- ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
- ctrl &= ~(1 << BITS_CKE);
- pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
+static int __init pcie_clk_init(struct sh7786_pcie_port *port)
+{
+ struct pci_channel *chan = port->hose;
+ struct clk *clk;
+ char fclk_name[16];
+ int ret;
+
+ /*
+ * First register the fixed clock
+ */
+ ret = clk_register(&fixed_pciexclkp);
+ if (unlikely(ret != 0))
+ return ret;
+
+ /*
+ * Grab the port's function clock, which the PHY clock depends
+ * on. clock lookups don't help us much at this point, since no
+ * dev_id is available this early. Lame.
+ */
+ snprintf(fclk_name, sizeof(fclk_name), "pcie%d_fck", port->index);
+
+ port->fclk = clk_get(NULL, fclk_name);
+ if (IS_ERR(port->fclk)) {
+ ret = PTR_ERR(port->fclk);
+ goto err_fclk;
+ }
+
+ clk_enable(port->fclk);
+
+ /*
+ * And now, set up the PHY clock
+ */
+ clk = &port->phy_clk;
+
+ memset(clk, 0, sizeof(struct clk));
+
+ clk->parent = &fixed_pciexclkp;
+ clk->enable_reg = (void __iomem *)(chan->reg_base + SH4A_PCIEPHYCTLR);
+ clk->enable_bit = BITS_CKE;
+
+ ret = sh_clk_mstp32_register(clk, 1);
+ if (unlikely(ret < 0))
+ goto err_phy;
+
+ return 0;
+
+err_phy:
+ clk_disable(port->fclk);
+ clk_put(port->fclk);
+err_fclk:
+ clk_unregister(&fixed_pciexclkp);
+
+ return ret;
}
-static int phy_init(struct pci_channel *chan)
+static int __init phy_init(struct sh7786_pcie_port *port)
{
+ struct pci_channel *chan = port->hose;
unsigned int timeout = 100;
+ clk_enable(&port->phy_clk);
+
/* Initialize the phy */
phy_write_reg(chan, 0x60, 0xf, 0x004b008b);
phy_write_reg(chan, 0x61, 0xf, 0x00007b41);
@@ -187,9 +265,13 @@ static int phy_init(struct pci_channel *chan)
phy_write_reg(chan, 0x66, 0xf, 0x00000010);
phy_write_reg(chan, 0x74, 0xf, 0x0007001c);
phy_write_reg(chan, 0x79, 0xf, 0x01fc000d);
+ phy_write_reg(chan, 0xb0, 0xf, 0x00000610);
/* Deassert Standby */
- phy_write_reg(chan, 0x67, 0xf, 0x00000400);
+ phy_write_reg(chan, 0x67, 0x1, 0x00000400);
+
+ /* Disable clock */
+ clk_disable(&port->phy_clk);
while (timeout--) {
if (pci_read_reg(chan, SH4A_PCIEPHYSR))
@@ -201,22 +283,33 @@ static int phy_init(struct pci_channel *chan)
return -ETIMEDOUT;
}
-static int pcie_init(struct sh7786_pcie_port *port)
+static void __init pcie_reset(struct sh7786_pcie_port *port)
+{
+ struct pci_channel *chan = port->hose;
+
+ pci_write_reg(chan, 1, SH4A_PCIESRSTR);
+ pci_write_reg(chan, 0, SH4A_PCIETCTLR);
+ pci_write_reg(chan, 0, SH4A_PCIESRSTR);
+ pci_write_reg(chan, 0, SH4A_PCIETXVC0SR);
+}
+
+static int __init pcie_init(struct sh7786_pcie_port *port)
{
struct pci_channel *chan = port->hose;
unsigned int data;
phys_addr_t memphys;
size_t memsize;
- int ret, i;
+ int ret, i, win;
/* Begin initialization */
- pci_write_reg(chan, 0, SH4A_PCIETCTLR);
+ pcie_reset(port);
- /* Initialize as type1. */
- data = pci_read_reg(chan, SH4A_PCIEPCICONF3);
- data &= ~(0x7f << 16);
- data |= PCI_HEADER_TYPE_BRIDGE << 16;
- pci_write_reg(chan, data, SH4A_PCIEPCICONF3);
+ /*
+ * Initial header for port config space is type 1, set the device
+ * class to match. Hardware takes care of propagating the IDSETR
+ * settings, so there is no need to bother with a quirk.
+ */
+ pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI << 16, SH4A_PCIEIDSETR1);
/* Initialize default capabilities. */
data = pci_read_reg(chan, SH4A_PCIEEXPCAP0);
@@ -268,30 +361,33 @@ static int pcie_init(struct sh7786_pcie_port *port)
* LAR1/LAMR1.
*/
if (memsize > SZ_512M) {
- __raw_writel(memphys + SZ_512M, chan->reg_base + SH4A_PCIELAR1);
- __raw_writel(((memsize - SZ_512M) - SZ_256) | 1,
- chan->reg_base + SH4A_PCIELAMR1);
+ pci_write_reg(chan, memphys + SZ_512M, SH4A_PCIELAR1);
+ pci_write_reg(chan, ((memsize - SZ_512M) - SZ_256) | 1,
+ SH4A_PCIELAMR1);
memsize = SZ_512M;
} else {
/*
* Otherwise just zero it out and disable it.
*/
- __raw_writel(0, chan->reg_base + SH4A_PCIELAR1);
- __raw_writel(0, chan->reg_base + SH4A_PCIELAMR1);
+ pci_write_reg(chan, 0, SH4A_PCIELAR1);
+ pci_write_reg(chan, 0, SH4A_PCIELAMR1);
}
/*
* LAR0/LAMR0 covers up to the first 512MB, which is enough to
* cover all of lowmem on most platforms.
*/
- __raw_writel(memphys, chan->reg_base + SH4A_PCIELAR0);
- __raw_writel((memsize - SZ_256) | 1, chan->reg_base + SH4A_PCIELAMR0);
+ pci_write_reg(chan, memphys, SH4A_PCIELAR0);
+ pci_write_reg(chan, (memsize - SZ_256) | 1, SH4A_PCIELAMR0);
/* Finish initialization */
data = pci_read_reg(chan, SH4A_PCIETCTLR);
data |= 0x1;
pci_write_reg(chan, data, SH4A_PCIETCTLR);
+ /* Let things settle down a bit.. */
+ mdelay(100);
+
/* Enable DL_Active Interrupt generation */
data = pci_read_reg(chan, SH4A_PCIEDLINTENR);
data |= PCIEDLINTENR_DLL_ACT_ENABLE;
@@ -302,9 +398,12 @@ static int pcie_init(struct sh7786_pcie_port *port)
data |= PCIEMACCTLR_SCR_DIS | (0xff << 16);
pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
+ /*
+ * This will timeout if we don't have a link, but we permit the
+ * port to register anyways in order to support hotplug on future
+ * hardware.
+ */
ret = pci_wait_for_irq(chan, MASK_INT_TX_CTRL);
- if (unlikely(ret != 0))
- return -ENODEV;
data = pci_read_reg(chan, SH4A_PCIEPCICONF1);
data &= ~(PCI_STATUS_DEVSEL_MASK << 16);
@@ -317,35 +416,48 @@ static int pcie_init(struct sh7786_pcie_port *port)
wmb();
- data = pci_read_reg(chan, SH4A_PCIEMACSR);
- printk(KERN_NOTICE "PCI: PCIe#%d link width %d\n",
- port->index, (data >> 20) & 0x3f);
-
+ if (ret == 0) {
+ data = pci_read_reg(chan, SH4A_PCIEMACSR);
+ printk(KERN_NOTICE "PCI: PCIe#%d x%d link detected\n",
+ port->index, (data >> 20) & 0x3f);
+ } else
+ printk(KERN_NOTICE "PCI: PCIe#%d link down\n",
+ port->index);
- for (i = 0; i < chan->nr_resources; i++) {
+ for (i = win = 0; i < chan->nr_resources; i++) {
struct resource *res = chan->resources + i;
resource_size_t size;
- u32 enable_mask;
+ u32 mask;
- pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(i));
+ /*
+ * We can't use the 32-bit mode windows in legacy 29-bit
+ * mode, so just skip them entirely.
+ */
+ if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode())
+ continue;
- size = resource_size(res);
+ pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(win));
/*
* The PAMR mask is calculated in units of 256kB, which
* keeps things pretty simple.
*/
- __raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18,
- chan->reg_base + SH4A_PCIEPAMR(i));
+ size = resource_size(res);
+ mask = (roundup_pow_of_two(size) / SZ_256K) - 1;
+ pci_write_reg(chan, mask << 18, SH4A_PCIEPAMR(win));
- pci_write_reg(chan, 0x00000000, SH4A_PCIEPARH(i));
- pci_write_reg(chan, 0x00000000, SH4A_PCIEPARL(i));
+ pci_write_reg(chan, upper_32_bits(res->start),
+ SH4A_PCIEPARH(win));
+ pci_write_reg(chan, lower_32_bits(res->start),
+ SH4A_PCIEPARL(win));
- enable_mask = MASK_PARE;
+ mask = MASK_PARE;
if (res->flags & IORESOURCE_IO)
- enable_mask |= MASK_SPC;
+ mask |= MASK_SPC;
+
+ pci_write_reg(chan, mask, SH4A_PCIEPTCTLR(win));
- pci_write_reg(chan, enable_mask, SH4A_PCIEPTCTLR(i));
+ win++;
}
return 0;
@@ -356,26 +468,33 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
return 71;
}
-static int sh7786_pcie_core_init(void)
+static int __init sh7786_pcie_core_init(void)
{
/* Return the number of ports */
return test_mode_pin(MODE_PIN12) ? 3 : 2;
}
-static int __devinit sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
+static int __init sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
{
int ret;
- ret = phy_init(port->hose);
- if (unlikely(ret < 0))
- return ret;
-
/*
* Check if we are configured in endpoint or root complex mode,
* this is a fixed pin setting that applies to all PCIe ports.
*/
port->endpoint = test_mode_pin(MODE_PIN11);
+ /*
+ * Setup clocks, needed both for PHY and PCIe registers.
+ */
+ ret = pcie_clk_init(port);
+ if (unlikely(ret < 0))
+ return ret;
+
+ ret = phy_init(port);
+ if (unlikely(ret < 0))
+ return ret;
+
ret = pcie_init(port);
if (unlikely(ret < 0))
return ret;
@@ -390,9 +509,10 @@ static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = {
static int __init sh7786_pcie_init(void)
{
+ struct clk *platclk;
int ret = 0, i;
- printk(KERN_NOTICE "PCI: Starting intialization.\n");
+ printk(KERN_NOTICE "PCI: Starting initialization.\n");
sh7786_pcie_hwops = &sh7786_65nm_pcie_hwops;
@@ -407,6 +527,22 @@ static int __init sh7786_pcie_init(void)
if (unlikely(!sh7786_pcie_ports))
return -ENOMEM;
+ /*
+ * Fetch any optional platform clock associated with this block.
+ *
+ * This is a rather nasty hack for boards with spec-mocking FPGAs
+ * that have a secondary set of clocks outside of the on-chip
+ * ones that need to be accounted for before there is any chance
+ * of touching the existing MSTP bits or CPG clocks.
+ */
+ platclk = clk_get(NULL, "pcie_plat_clk");
+ if (IS_ERR(platclk)) {
+ /* Sane hardware should probably get a WARN_ON.. */
+ platclk = NULL;
+ }
+
+ clk_enable(platclk);
+
printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports);
for (i = 0; i < nr_ports; i++) {
@@ -419,8 +555,11 @@ static int __init sh7786_pcie_init(void)
ret |= sh7786_pcie_hwops->port_init_hw(port);
}
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ clk_disable(platclk);
+ clk_put(platclk);
return ret;
+ }
return 0;
}
diff --git a/arch/sh/drivers/pci/pcie-sh7786.h b/arch/sh/drivers/pci/pcie-sh7786.h
index 90a6992576b0..1ee054e47eae 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.h
+++ b/arch/sh/drivers/pci/pcie-sh7786.h
@@ -55,8 +55,11 @@
#define BITS_ERRRCV (0) /* 0 ERRRCV 0 */
#define MASK_ERRRCV (1<<BITS_ERRRCV)
+/* PCIEENBLR */
+#define SH4A_PCIEENBLR (0x000008) /* R/W - 0x0000 0001 32 */
+
/* PCIEECR */
-#define SH4A_PCIEECR (0x000008) /* R/W - 0x0000 0000 32 */
+#define SH4A_PCIEECR (0x00000C) /* R/W - 0x0000 0000 32 */
#define BITS_ENBL (0) /* 0 ENBL 0 R/W */
#define MASK_ENBL (1<<BITS_ENBL)
@@ -113,6 +116,27 @@
#define BITS_MDATA (0)
#define MASK_MDATA (0xffffffff<<BITS_MDATA)
+/* PCIEUNLOCKCR */
+#define SH4A_PCIEUNLOCKCR (0x000048) /* R/W - 0x0000 0000 32 */
+
+/* PCIEIDR */
+#define SH4A_PCIEIDR (0x000060) /* R/W - 0x0101 1101 32 */
+
+/* PCIEDBGCTLR */
+#define SH4A_PCIEDBGCTLR (0x000100) /* R/W - 0x0000 0000 32 */
+
+/* PCIEINTXR */
+#define SH4A_PCIEINTXR (0x004000) /* R/W - 0x0000 0000 32 */
+
+/* PCIERMSGR */
+#define SH4A_PCIERMSGR (0x004010) /* R/W - 0x0000 0000 32 */
+
+/* PCIERSTR */
+#define SH4A_PCIERSTR(x) (0x008000 + ((x) * 0x4)) /* R/W - 0x0000 0000 32 */
+
+/* PCIESRSTR */
+#define SH4A_PCIESRSTR (0x008040) /* R/W - 0x0000 0000 32 */
+
/* PCIEPHYCTLR */
#define SH4A_PCIEPHYCTLR (0x010000) /* R/W - 0x0000 0000 32 */
#define BITS_CKE (0)
@@ -121,6 +145,9 @@
/* PCIERMSGIER */
#define SH4A_PCIERMSGIER (0x004040) /* R/W - 0x0000 0000 32 */
+/* PCIEPHYCTLR */
+#define SH4A_PCIEPHYCTLR (0x010000) /* R/W - 0x0000 0000 32 */
+
/* PCIEPHYADRR */
#define SH4A_PCIEPHYADRR (0x010004) /* R/W - 0x0000 0000 32 */
#define BITS_ACK (24) // Rev1.171
@@ -152,7 +179,7 @@
#define MASK_CFINT (1<<BITS_CFINT)
/* PCIETSTR */
-#define SH4A_PCIETSTR (0x020004) /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIETSTR (0x020004) /* R 0x0000 0000 32 */
/* PCIEINTR */
#define SH4A_PCIEINTR (0x020008) /* R/W R/W 0x0000 0000 32 */
@@ -236,6 +263,9 @@
#define BITS_INTPM (8)
#define MASK_INTPM (1<<BITS_INTPM)
+/* PCIEEH0R */
+#define SH4A_PCIEEHR(x) (0x020010 + ((x) * 0x4)) /* R - 0x0000 0000 32 */
+
/* PCIEAIR */
#define SH4A_PCIEAIR (SH4A_PCIE_BASE + 0x020010) /* R/W R/W 0xxxxx xxxx 32 */
@@ -244,6 +274,25 @@
/* PCIEERRFR */ // Rev1.18
#define SH4A_PCIEERRFR (0x020020) /* R/W R/W 0xxxxx xxxx 32 */ // Rev1.18
+
+/* PCIEERRFER */
+#define SH4A_PCIEERRFER (0x020024) /* R/W R/W 0x0000 0000 32 */
+
+/* PCIEERRFR2 */
+#define SH4A_PCIEERRFR2 (0x020028) /* R/W R/W 0x0000 0000 32 */
+
+/* PCIEMSIR */
+#define SH4A_PCIEMSIR (0x020040) /* R/W - 0x0000 0000 32 */
+
+/* PCIEMSIFR */
+#define SH4A_PCIEMSIFR (0x020044) /* R/W R/W 0x0000 0000 32 */
+
+/* PCIEPWRCTLR */
+#define SH4A_PCIEPWRCTLR (0x020100) /* R/W - 0x0000 0000 32 */
+
+/* PCIEPCCTLR */
+#define SH4A_PCIEPCCTLR (0x020180) /* R/W - 0x0000 0000 32 */
+
// Rev1.18
/* PCIELAR0 */
#define SH4A_PCIELAR0 (0x020200) /* R/W R/W 0x0000 0000 32 */
@@ -352,6 +401,7 @@
#define SH4A_PCIEDMCCR0 (0x021120) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMCC2R0 (0x021124) /* R/W R/W 0x0000 0000 - */
#define SH4A_PCIEDMCCCR0 (0x021128) /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR0 (0x02112C) /* R/W - 0x0000 0000 32 */
#define SH4A_PCIEDMSAR1 (0x021140) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMSAHR1 (0x021144) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMDAR1 (0x021148) /* R/W R/W 0x0000 0000 32 */
@@ -363,6 +413,7 @@
#define SH4A_PCIEDMCCR1 (0x021160) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMCC2R1 (0x021164) /* R/W R/W 0x0000 0000 - */
#define SH4A_PCIEDMCCCR1 (0x021168) /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR1 (0x02116C) /* R/W - 0x0000 0000 32 */
#define SH4A_PCIEDMSAR2 (0x021180) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMSAHR2 (0x021184) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMDAR2 (0x021188) /* R/W R/W 0x0000 0000 32 */
@@ -385,6 +436,7 @@
#define SH4A_PCIEDMCCR3 (0x0211E0) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMCC2R3 (0x0211E4) /* R/W R/W 0x0000 0000 - */
#define SH4A_PCIEDMCCCR3 (0x0211E8) /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR3 (0x0211EC) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEPCICONF0 (0x040000) /* R R - 8/16/32 */
#define SH4A_PCIEPCICONF1 (0x040004) /* R/W R/W 0x0008 0000 8/16/32 */
#define SH4A_PCIEPCICONF2 (0x040008) /* R/W R/W 0xFF00 0000 8/16/32 */
diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild
index 0eed47b236ab..7beb42322f60 100644
--- a/arch/sh/include/asm/Kbuild
+++ b/arch/sh/include/asm/Kbuild
@@ -5,5 +5,7 @@ header-y += cpu-features.h
header-y += hw_breakpoint.h
header-y += posix_types_32.h
header-y += posix_types_64.h
+header-y += ptrace_32.h
+header-y += ptrace_64.h
header-y += unistd_32.h
header-y += unistd_64.h
diff --git a/arch/sh/include/asm/elf.h b/arch/sh/include/asm/elf.h
index ce830faeebbf..f38112be67d2 100644
--- a/arch/sh/include/asm/elf.h
+++ b/arch/sh/include/asm/elf.h
@@ -50,25 +50,14 @@
#define R_SH_GOTPC 167
/* FDPIC relocs */
-#define R_SH_GOT20 70
-#define R_SH_GOTOFF20 71
-#define R_SH_GOTFUNCDESC 72
-#define R_SH_GOTFUNCDESC20 73
-#define R_SH_GOTOFFFUNCDESC 74
-#define R_SH_GOTOFFFUNCDESC20 75
-#define R_SH_FUNCDESC 76
-#define R_SH_FUNCDESC_VALUE 77
-
-#if 0 /* XXX - later .. */
-#define R_SH_GOT20 198
-#define R_SH_GOTOFF20 199
-#define R_SH_GOTFUNCDESC 200
-#define R_SH_GOTFUNCDESC20 201
-#define R_SH_GOTOFFFUNCDESC 202
-#define R_SH_GOTOFFFUNCDESC20 203
-#define R_SH_FUNCDESC 204
-#define R_SH_FUNCDESC_VALUE 205
-#endif
+#define R_SH_GOT20 201
+#define R_SH_GOTOFF20 202
+#define R_SH_GOTFUNCDESC 203
+#define R_SH_GOTFUNCDESC20 204
+#define R_SH_GOTOFFFUNCDESC 205
+#define R_SH_GOTOFFFUNCDESC20 206
+#define R_SH_FUNCDESC 207
+#define R_SH_FUNCDESC_VALUE 208
/* SHmedia relocs */
#define R_SH_IMM_LOW16 246
diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h
index 6e7cea453895..bd7e79a12653 100644
--- a/arch/sh/include/asm/fixmap.h
+++ b/arch/sh/include/asm/fixmap.h
@@ -58,7 +58,7 @@ enum fixed_addresses {
#ifdef CONFIG_HIGHMEM
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
- FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+ FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1,
#endif
#ifdef CONFIG_IOREMAP_FIXED
@@ -69,7 +69,7 @@ enum fixed_addresses {
*/
#define FIX_N_IOREMAPS 32
FIX_IOREMAP_BEGIN,
- FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS,
+ FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS - 1,
#endif
__end_of_fixed_addresses
diff --git a/arch/sh/include/asm/gpio.h b/arch/sh/include/asm/gpio.h
index f8d9a731e903..04f53d31489f 100644
--- a/arch/sh/include/asm/gpio.h
+++ b/arch/sh/include/asm/gpio.h
@@ -41,14 +41,12 @@ static inline int gpio_cansleep(unsigned gpio)
static inline int gpio_to_irq(unsigned gpio)
{
- WARN_ON(1);
- return -ENOSYS;
+ return __gpio_to_irq(gpio);
}
static inline int irq_to_gpio(unsigned int irq)
{
- WARN_ON(1);
- return -EINVAL;
+ return -ENOSYS;
}
#endif /* CONFIG_GPIOLIB */
diff --git a/arch/sh/include/asm/irq.h b/arch/sh/include/asm/irq.h
index 02c2f0102cfa..45d08b6a5ef7 100644
--- a/arch/sh/include/asm/irq.h
+++ b/arch/sh/include/asm/irq.h
@@ -9,7 +9,7 @@
* advised to cap this at the hard limit that they're interested in
* through the machvec.
*/
-#define NR_IRQS 256
+#define NR_IRQS 512
#define NR_IRQS_LEGACY 8 /* Legacy external IRQ0-7 */
/*
diff --git a/arch/sh/include/asm/kprobes.h b/arch/sh/include/asm/kprobes.h
index 036c3311233c..134f3980e44a 100644
--- a/arch/sh/include/asm/kprobes.h
+++ b/arch/sh/include/asm/kprobes.h
@@ -16,7 +16,6 @@ typedef insn_size_t kprobe_opcode_t;
? (MAX_STACK_SIZE) \
: (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
-#define regs_return_value(_regs) ((_regs)->regs[0])
#define flush_insn_slot(p) do { } while (0)
#define kretprobe_blacklist_size 0
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 8bd952fcf3ba..f0efe97f1750 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -37,6 +37,8 @@ struct pci_channel {
};
/* arch/sh/drivers/pci/pci.c */
+extern raw_spinlock_t pci_config_lock;
+
extern int register_pci_controller(struct pci_channel *hose);
extern void pcibios_report_status(unsigned int status_mask, int warn);
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index 61a445d2d02a..46d5179c9f49 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -13,7 +13,6 @@
#include <linux/linkage.h>
#include <asm/page.h>
#include <asm/types.h>
-#include <asm/ptrace.h>
#include <asm/hw_breakpoint.h>
/*
@@ -194,8 +193,6 @@ extern unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[15])
-#define user_stack_pointer(_regs) ((_regs)->regs[15])
-
#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4)
#define PREFETCH_STRIDE L1_CACHE_BYTES
#define ARCH_HAS_PREFETCH
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h
index 621bc4618c6b..2a541ddb5a1b 100644
--- a/arch/sh/include/asm/processor_64.h
+++ b/arch/sh/include/asm/processor_64.h
@@ -17,7 +17,6 @@
#include <linux/compiler.h>
#include <asm/page.h>
#include <asm/types.h>
-#include <asm/ptrace.h>
#include <cpu/registers.h>
/*
@@ -231,7 +230,5 @@ extern unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) ((tsk)->thread.pc)
#define KSTK_ESP(tsk) ((tsk)->thread.sp)
-#define user_stack_pointer(_regs) ((_regs)->regs[15])
-
#endif /* __ASSEMBLY__ */
#endif /* __ASM_SH_PROCESSOR_64_H */
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h
index 2168fde25611..f6edc10aa0d3 100644
--- a/arch/sh/include/asm/ptrace.h
+++ b/arch/sh/include/asm/ptrace.h
@@ -3,90 +3,7 @@
/*
* Copyright (C) 1999, 2000 Niibe Yutaka
- *
- */
-#if defined(__SH5__)
-struct pt_regs {
- unsigned long long pc;
- unsigned long long sr;
- long long syscall_nr;
- unsigned long long regs[63];
- unsigned long long tregs[8];
- unsigned long long pad[2];
-};
-#else
-/*
- * GCC defines register number like this:
- * -----------------------------
- * 0 - 15 are integer registers
- * 17 - 22 are control/special registers
- * 24 - 39 fp registers
- * 40 - 47 xd registers
- * 48 - fpscr register
- * -----------------------------
- *
- * We follows above, except:
- * 16 --- program counter (PC)
- * 22 --- syscall #
- * 23 --- floating point communication register
*/
-#define REG_REG0 0
-#define REG_REG15 15
-
-#define REG_PC 16
-
-#define REG_PR 17
-#define REG_SR 18
-#define REG_GBR 19
-#define REG_MACH 20
-#define REG_MACL 21
-
-#define REG_SYSCALL 22
-
-#define REG_FPREG0 23
-#define REG_FPREG15 38
-#define REG_XFREG0 39
-#define REG_XFREG15 54
-
-#define REG_FPSCR 55
-#define REG_FPUL 56
-
-/*
- * This struct defines the way the registers are stored on the
- * kernel stack during a system call or other kernel entry.
- */
-struct pt_regs {
- unsigned long regs[16];
- unsigned long pc;
- unsigned long pr;
- unsigned long sr;
- unsigned long gbr;
- unsigned long mach;
- unsigned long macl;
- long tra;
-};
-
-/*
- * This struct defines the way the DSP registers are stored on the
- * kernel stack during a system call or other kernel entry.
- */
-struct pt_dspregs {
- unsigned long a1;
- unsigned long a0g;
- unsigned long a1g;
- unsigned long m0;
- unsigned long m1;
- unsigned long a0;
- unsigned long x0;
- unsigned long x1;
- unsigned long y0;
- unsigned long y1;
- unsigned long dsr;
- unsigned long rs;
- unsigned long re;
- unsigned long mod;
-};
-#endif
#define PTRACE_GETREGS 12 /* General registers */
#define PTRACE_SETREGS 13
@@ -107,22 +24,102 @@ struct pt_dspregs {
#define PT_DATA_ADDR 248 /* &(struct user)->start_data */
#define PT_TEXT_LEN 252
+#if defined(__SH5__) || defined(CONFIG_CPU_SH5)
+#include "ptrace_64.h"
+#else
+#include "ptrace_32.h"
+#endif
+
#ifdef __KERNEL__
+
+#include <linux/stringify.h>
+#include <linux/stddef.h>
+#include <linux/thread_info.h>
#include <asm/addrspace.h>
#include <asm/page.h>
#include <asm/system.h>
#define user_mode(regs) (((regs)->sr & 0x40000000)==0)
+#define user_stack_pointer(regs) ((unsigned long)(regs)->regs[15])
+#define kernel_stack_pointer(regs) ((unsigned long)(regs)->regs[15])
#define instruction_pointer(regs) ((unsigned long)(regs)->pc)
extern void show_regs(struct pt_regs *);
+#define arch_has_single_step() (1)
+
/*
- * These are defined as per linux/ptrace.h.
+ * kprobe-based event tracer support
*/
-struct task_struct;
+struct pt_regs_offset {
+ const char *name;
+ int offset;
+};
-#define arch_has_single_step() (1)
+#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
+#define REGS_OFFSET_NAME(num) \
+ {.name = __stringify(r##num), .offset = offsetof(struct pt_regs, regs[num])}
+#define TREGS_OFFSET_NAME(num) \
+ {.name = __stringify(tr##num), .offset = offsetof(struct pt_regs, tregs[num])}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+/* Query offset/name of register from its name/offset */
+extern int regs_query_register_offset(const char *name);
+extern const char *regs_query_register_name(unsigned int offset);
+
+extern const struct pt_regs_offset regoffset_table[];
+
+/**
+ * regs_get_register() - get register value from its offset
+ * @regs: pt_regs from which register value is gotten.
+ * @offset: offset number of the register.
+ *
+ * regs_get_register returns the value of a register. The @offset is the
+ * offset of the register in struct pt_regs address which specified by @regs.
+ * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
+ */
+static inline unsigned long regs_get_register(struct pt_regs *regs,
+ unsigned int offset)
+{
+ if (unlikely(offset > MAX_REG_OFFSET))
+ return 0;
+ return *(unsigned long *)((unsigned long)regs + offset);
+}
+
+/**
+ * regs_within_kernel_stack() - check the address in the stack
+ * @regs: pt_regs which contains kernel stack pointer.
+ * @addr: address which is checked.
+ *
+ * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
+ * If @addr is within the kernel stack, it returns true. If not, returns false.
+ */
+static inline int regs_within_kernel_stack(struct pt_regs *regs,
+ unsigned long addr)
+{
+ return ((addr & ~(THREAD_SIZE - 1)) ==
+ (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
+}
+
+/**
+ * regs_get_kernel_stack_nth() - get Nth entry of the stack
+ * @regs: pt_regs which contains kernel stack pointer.
+ * @n: stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * this returns 0.
+ */
+static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
+ unsigned int n)
+{
+ unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+ addr += n;
+ if (regs_within_kernel_stack(regs, (unsigned long)addr))
+ return *addr;
+ else
+ return 0;
+}
struct perf_event;
struct perf_sample_data;
diff --git a/arch/sh/include/asm/ptrace_32.h b/arch/sh/include/asm/ptrace_32.h
new file mode 100644
index 000000000000..35d9e257558c
--- /dev/null
+++ b/arch/sh/include/asm/ptrace_32.h
@@ -0,0 +1,83 @@
+#ifndef __ASM_SH_PTRACE_32_H
+#define __ASM_SH_PTRACE_32_H
+
+/*
+ * GCC defines register number like this:
+ * -----------------------------
+ * 0 - 15 are integer registers
+ * 17 - 22 are control/special registers
+ * 24 - 39 fp registers
+ * 40 - 47 xd registers
+ * 48 - fpscr register
+ * -----------------------------
+ *
+ * We follows above, except:
+ * 16 --- program counter (PC)
+ * 22 --- syscall #
+ * 23 --- floating point communication register
+ */
+#define REG_REG0 0
+#define REG_REG15 15
+
+#define REG_PC 16
+
+#define REG_PR 17
+#define REG_SR 18
+#define REG_GBR 19
+#define REG_MACH 20
+#define REG_MACL 21
+
+#define REG_SYSCALL 22
+
+#define REG_FPREG0 23
+#define REG_FPREG15 38
+#define REG_XFREG0 39
+#define REG_XFREG15 54
+
+#define REG_FPSCR 55
+#define REG_FPUL 56
+
+/*
+ * This struct defines the way the registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ */
+struct pt_regs {
+ unsigned long regs[16];
+ unsigned long pc;
+ unsigned long pr;
+ unsigned long sr;
+ unsigned long gbr;
+ unsigned long mach;
+ unsigned long macl;
+ long tra;
+};
+
+/*
+ * This struct defines the way the DSP registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ */
+struct pt_dspregs {
+ unsigned long a1;
+ unsigned long a0g;
+ unsigned long a1g;
+ unsigned long m0;
+ unsigned long m1;
+ unsigned long a0;
+ unsigned long x0;
+ unsigned long x1;
+ unsigned long y0;
+ unsigned long y1;
+ unsigned long dsr;
+ unsigned long rs;
+ unsigned long re;
+ unsigned long mod;
+};
+
+#ifdef __KERNEL__
+
+#define MAX_REG_OFFSET offsetof(struct pt_regs, tra)
+#define regs_return_value(regs) ((regs)->regs[0])
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_SH_PTRACE_32_H */
diff --git a/arch/sh/include/asm/ptrace_64.h b/arch/sh/include/asm/ptrace_64.h
new file mode 100644
index 000000000000..d43c1cb0bbe7
--- /dev/null
+++ b/arch/sh/include/asm/ptrace_64.h
@@ -0,0 +1,20 @@
+#ifndef __ASM_SH_PTRACE_64_H
+#define __ASM_SH_PTRACE_64_H
+
+struct pt_regs {
+ unsigned long long pc;
+ unsigned long long sr;
+ long long syscall_nr;
+ unsigned long long regs[63];
+ unsigned long long tregs[8];
+ unsigned long long pad[2];
+};
+
+#ifdef __KERNEL__
+
+#define MAX_REG_OFFSET offsetof(struct pt_regs, tregs[7])
+#define regs_return_value(regs) ((regs)->regs[3])
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_SH_PTRACE_64_H */
diff --git a/arch/sh/include/asm/sizes.h b/arch/sh/include/asm/sizes.h
index 3a1fb97770f1..0b9fe2d5c36d 100644
--- a/arch/sh/include/asm/sizes.h
+++ b/arch/sh/include/asm/sizes.h
@@ -32,6 +32,7 @@
#define SZ_512 0x00000200
#define SZ_1K 0x00000400
+#define SZ_2K 0x00000800
#define SZ_4K 0x00001000
#define SZ_8K 0x00002000
#define SZ_16K 0x00004000
diff --git a/arch/sh/include/asm/sram.h b/arch/sh/include/asm/sram.h
new file mode 100644
index 000000000000..a2808ce4c0aa
--- /dev/null
+++ b/arch/sh/include/asm/sram.h
@@ -0,0 +1,38 @@
+#ifndef __ASM_SRAM_H
+#define __ASM_SRAM_H
+
+#ifdef CONFIG_HAVE_SRAM_POOL
+
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+
+/* arch/sh/mm/sram.c */
+extern struct gen_pool *sram_pool;
+
+static inline unsigned long sram_alloc(size_t len)
+{
+ if (!sram_pool)
+ return 0UL;
+
+ return gen_pool_alloc(sram_pool, len);
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+ return gen_pool_free(sram_pool, addr, len);
+}
+
+#else
+
+static inline unsigned long sram_alloc(size_t len)
+{
+ return 0;
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+}
+
+#endif /* CONFIG_HAVE_SRAM_POOL */
+
+#endif /* __ASM_SRAM_H */
diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h
index 0bd7a17d5e1a..1f1af5afff03 100644
--- a/arch/sh/include/asm/system.h
+++ b/arch/sh/include/asm/system.h
@@ -140,8 +140,6 @@ extern unsigned int instruction_size(unsigned int insn);
extern unsigned long cached_to_uncached;
extern unsigned long uncached_size;
-extern struct dentry *sh_debugfs_root;
-
void per_cpu_trap_init(void);
void default_idle(void);
void cpu_idle_wait(void);
diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h
index 51296b36770e..c941b2739405 100644
--- a/arch/sh/include/asm/system_32.h
+++ b/arch/sh/include/asm/system_32.h
@@ -212,17 +212,16 @@ static inline reg_size_t register_align(void *val)
}
int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
- struct mem_access *ma, int);
+ struct mem_access *ma, int, unsigned long address);
static inline void trigger_address_error(void)
{
- if (__in_29bit_mode())
- __asm__ __volatile__ (
- "ldc %0, sr\n\t"
- "mov.l @%1, %0"
- :
- : "r" (0x10000000), "r" (0x80000001)
- );
+ __asm__ __volatile__ (
+ "ldc %0, sr\n\t"
+ "mov.l @%1, %0"
+ :
+ : "r" (0x10000000), "r" (0x80000001)
+ );
}
asmlinkage void do_address_error(struct pt_regs *regs,
diff --git a/arch/sh/include/asm/tlbflush.h b/arch/sh/include/asm/tlbflush.h
index e0ac97221ae6..0df66f0c7284 100644
--- a/arch/sh/include/asm/tlbflush.h
+++ b/arch/sh/include/asm/tlbflush.h
@@ -21,6 +21,8 @@ extern void local_flush_tlb_kernel_range(unsigned long start,
unsigned long end);
extern void local_flush_tlb_one(unsigned long asid, unsigned long page);
+extern void __flush_tlb_global(void);
+
#ifdef CONFIG_SMP
extern void flush_tlb_all(void);
diff --git a/arch/sh/include/asm/unistd_32.h b/arch/sh/include/asm/unistd_32.h
index 0e7f0fc8f086..903cd618eb74 100644
--- a/arch/sh/include/asm/unistd_32.h
+++ b/arch/sh/include/asm/unistd_32.h
@@ -345,12 +345,33 @@
#define __NR_pwritev 334
#define __NR_rt_tgsigqueueinfo 335
#define __NR_perf_event_open 336
+#define __NR_fanotify_init 337
+#define __NR_fanotify_mark 338
+#define __NR_prlimit64 339
-#define NR_syscalls 337
+/* Non-multiplexed socket family */
+#define __NR_socket 340
+#define __NR_bind 341
+#define __NR_connect 342
+#define __NR_listen 343
+#define __NR_accept 344
+#define __NR_getsockname 345
+#define __NR_getpeername 346
+#define __NR_socketpair 347
+#define __NR_send 348
+#define __NR_sendto 349
+#define __NR_recv 350
+#define __NR_recvfrom 351
+#define __NR_shutdown 352
+#define __NR_setsockopt 353
+#define __NR_getsockopt 354
+#define __NR_sendmsg 355
+#define __NR_recvmsg 356
+#define __NR_recvmmsg 357
-#ifdef __KERNEL__
+#define NR_syscalls 358
-#define __IGNORE_recvmmsg
+#ifdef __KERNEL__
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/sh/include/asm/unistd_64.h b/arch/sh/include/asm/unistd_64.h
index 0580c33a1e04..09aa93f9eb70 100644
--- a/arch/sh/include/asm/unistd_64.h
+++ b/arch/sh/include/asm/unistd_64.h
@@ -387,10 +387,13 @@
#define __NR_perf_event_open 364
#define __NR_recvmmsg 365
#define __NR_accept4 366
+#define __NR_fanotify_init 367
+#define __NR_fanotify_mark 368
+#define __NR_prlimit64 369
#ifdef __KERNEL__
-#define NR_syscalls 367
+#define NR_syscalls 370
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/sh/include/cpu-sh3/cpu/mmu_context.h b/arch/sh/include/cpu-sh3/cpu/mmu_context.h
index ab09da73ce77..0c7c735ea82a 100644
--- a/arch/sh/include/cpu-sh3/cpu/mmu_context.h
+++ b/arch/sh/include/cpu-sh3/cpu/mmu_context.h
@@ -16,6 +16,7 @@
#define MMU_TEA 0xFFFFFFFC /* TLB Exception Address */
#define MMUCR 0xFFFFFFE0 /* MMU Control Register */
+#define MMUCR_TI (1 << 2) /* TLB flush bit */
#define MMU_TLB_ADDRESS_ARRAY 0xF2000000
#define MMU_PAGE_ASSOC_BIT 0x80
diff --git a/arch/sh/include/cpu-sh4/cpu/freq.h b/arch/sh/include/cpu-sh4/cpu/freq.h
index e1e90960ee9a..cffd25ed0240 100644
--- a/arch/sh/include/cpu-sh4/cpu/freq.h
+++ b/arch/sh/include/cpu-sh4/cpu/freq.h
@@ -56,7 +56,9 @@
#define FRQCR1 0xffc40004
#define FRQMR1 0xffc40014
#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
-#define FRQCR 0xffc00014
+#define FRQCR0 0xffc00000
+#define FRQCR1 0xffc00004
+#define FRQMR1 0xffc00014
#else
#define FRQCR 0xffc00000
#define FRQCR_PSTBY 0x0200
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7757.h b/arch/sh/include/cpu-sh4/cpu/sh7757.h
index f4d267efad71..15f3de11c55a 100644
--- a/arch/sh/include/cpu-sh4/cpu/sh7757.h
+++ b/arch/sh/include/cpu-sh4/cpu/sh7757.h
@@ -3,241 +3,252 @@
enum {
/* PTA */
- GPIO_PTA7, GPIO_PTA6, GPIO_PTA5, GPIO_PTA4,
- GPIO_PTA3, GPIO_PTA2, GPIO_PTA1, GPIO_PTA0,
+ GPIO_PTA0, GPIO_PTA1, GPIO_PTA2, GPIO_PTA3,
+ GPIO_PTA4, GPIO_PTA5, GPIO_PTA6, GPIO_PTA7,
/* PTB */
- GPIO_PTB7, GPIO_PTB6, GPIO_PTB5, GPIO_PTB4,
- GPIO_PTB3, GPIO_PTB2, GPIO_PTB1, GPIO_PTB0,
+ GPIO_PTB0, GPIO_PTB1, GPIO_PTB2, GPIO_PTB3,
+ GPIO_PTB4, GPIO_PTB5, GPIO_PTB6, GPIO_PTB7,
/* PTC */
- GPIO_PTC7, GPIO_PTC6, GPIO_PTC5, GPIO_PTC4,
- GPIO_PTC3, GPIO_PTC2, GPIO_PTC1, GPIO_PTC0,
+ GPIO_PTC0, GPIO_PTC1, GPIO_PTC2, GPIO_PTC3,
+ GPIO_PTC4, GPIO_PTC5, GPIO_PTC6, GPIO_PTC7,
/* PTD */
- GPIO_PTD7, GPIO_PTD6, GPIO_PTD5, GPIO_PTD4,
- GPIO_PTD3, GPIO_PTD2, GPIO_PTD1, GPIO_PTD0,
+ GPIO_PTD0, GPIO_PTD1, GPIO_PTD2, GPIO_PTD3,
+ GPIO_PTD4, GPIO_PTD5, GPIO_PTD6, GPIO_PTD7,
/* PTE */
- GPIO_PTE7, GPIO_PTE6, GPIO_PTE5, GPIO_PTE4,
- GPIO_PTE3, GPIO_PTE2, GPIO_PTE1, GPIO_PTE0,
+ GPIO_PTE0, GPIO_PTE1, GPIO_PTE2, GPIO_PTE3,
+ GPIO_PTE4, GPIO_PTE5, GPIO_PTE6, GPIO_PTE7,
/* PTF */
- GPIO_PTF7, GPIO_PTF6, GPIO_PTF5, GPIO_PTF4,
- GPIO_PTF3, GPIO_PTF2, GPIO_PTF1, GPIO_PTF0,
+ GPIO_PTF0, GPIO_PTF1, GPIO_PTF2, GPIO_PTF3,
+ GPIO_PTF4, GPIO_PTF5, GPIO_PTF6, GPIO_PTF7,
/* PTG */
- GPIO_PTG7, GPIO_PTG6, GPIO_PTG5, GPIO_PTG4,
- GPIO_PTG3, GPIO_PTG2, GPIO_PTG1, GPIO_PTG0,
+ GPIO_PTG0, GPIO_PTG1, GPIO_PTG2, GPIO_PTG3,
+ GPIO_PTG4, GPIO_PTG5, GPIO_PTG6, GPIO_PTG7,
/* PTH */
- GPIO_PTH7, GPIO_PTH6, GPIO_PTH5, GPIO_PTH4,
- GPIO_PTH3, GPIO_PTH2, GPIO_PTH1, GPIO_PTH0,
+ GPIO_PTH0, GPIO_PTH1, GPIO_PTH2, GPIO_PTH3,
+ GPIO_PTH4, GPIO_PTH5, GPIO_PTH6, GPIO_PTH7,
/* PTI */
- GPIO_PTI7, GPIO_PTI6, GPIO_PTI5, GPIO_PTI4,
- GPIO_PTI3, GPIO_PTI2, GPIO_PTI1, GPIO_PTI0,
+ GPIO_PTI0, GPIO_PTI1, GPIO_PTI2, GPIO_PTI3,
+ GPIO_PTI4, GPIO_PTI5, GPIO_PTI6, GPIO_PTI7,
/* PTJ */
- GPIO_PTJ7, GPIO_PTJ6, GPIO_PTJ5, GPIO_PTJ4,
- GPIO_PTJ3, GPIO_PTJ2, GPIO_PTJ1, GPIO_PTJ0,
+ GPIO_PTJ0, GPIO_PTJ1, GPIO_PTJ2, GPIO_PTJ3,
+ GPIO_PTJ4, GPIO_PTJ5, GPIO_PTJ6, GPIO_PTJ7_RESV,
/* PTK */
- GPIO_PTK7, GPIO_PTK6, GPIO_PTK5, GPIO_PTK4,
- GPIO_PTK3, GPIO_PTK2, GPIO_PTK1, GPIO_PTK0,
+ GPIO_PTK0, GPIO_PTK1, GPIO_PTK2, GPIO_PTK3,
+ GPIO_PTK4, GPIO_PTK5, GPIO_PTK6, GPIO_PTK7,
/* PTL */
- GPIO_PTL7, GPIO_PTL6, GPIO_PTL5, GPIO_PTL4,
- GPIO_PTL3, GPIO_PTL2, GPIO_PTL1, GPIO_PTL0,
+ GPIO_PTL0, GPIO_PTL1, GPIO_PTL2, GPIO_PTL3,
+ GPIO_PTL4, GPIO_PTL5, GPIO_PTL6, GPIO_PTL7_RESV,
/* PTM */
- GPIO_PTM6, GPIO_PTM5, GPIO_PTM4,
- GPIO_PTM3, GPIO_PTM2, GPIO_PTM1, GPIO_PTM0,
+ GPIO_PTM0, GPIO_PTM1, GPIO_PTM2, GPIO_PTM3,
+ GPIO_PTM4, GPIO_PTM5, GPIO_PTM6, GPIO_PTM7,
/* PTN */
- GPIO_PTN7, GPIO_PTN6, GPIO_PTN5, GPIO_PTN4,
- GPIO_PTN3, GPIO_PTN2, GPIO_PTN1, GPIO_PTN0,
+ GPIO_PTN0, GPIO_PTN1, GPIO_PTN2, GPIO_PTN3,
+ GPIO_PTN4, GPIO_PTN5, GPIO_PTN6, GPIO_PTN7_RESV,
/* PTO */
- GPIO_PTO7, GPIO_PTO6, GPIO_PTO5, GPIO_PTO4,
- GPIO_PTO3, GPIO_PTO2, GPIO_PTO1, GPIO_PTO0,
+ GPIO_PTO0, GPIO_PTO1, GPIO_PTO2, GPIO_PTO3,
+ GPIO_PTO4, GPIO_PTO5, GPIO_PTO6, GPIO_PTO7,
/* PTP */
- GPIO_PTP6, GPIO_PTP5, GPIO_PTP4,
- GPIO_PTP3, GPIO_PTP2, GPIO_PTP1, GPIO_PTP0,
+ GPIO_PTP0, GPIO_PTP1, GPIO_PTP2, GPIO_PTP3,
+ GPIO_PTP4, GPIO_PTP5, GPIO_PTP6, GPIO_PTP7,
/* PTQ */
- GPIO_PTQ6, GPIO_PTQ5, GPIO_PTQ4,
- GPIO_PTQ3, GPIO_PTQ2, GPIO_PTQ1, GPIO_PTQ0,
+ GPIO_PTQ0, GPIO_PTQ1, GPIO_PTQ2, GPIO_PTQ3,
+ GPIO_PTQ4, GPIO_PTQ5, GPIO_PTQ6, GPIO_PTQ7_RESV,
/* PTR */
- GPIO_PTR7, GPIO_PTR6, GPIO_PTR5, GPIO_PTR4,
- GPIO_PTR3, GPIO_PTR2, GPIO_PTR1, GPIO_PTR0,
+ GPIO_PTR0, GPIO_PTR1, GPIO_PTR2, GPIO_PTR3,
+ GPIO_PTR4, GPIO_PTR5, GPIO_PTR6, GPIO_PTR7,
/* PTS */
- GPIO_PTS7, GPIO_PTS6, GPIO_PTS5, GPIO_PTS4,
- GPIO_PTS3, GPIO_PTS2, GPIO_PTS1, GPIO_PTS0,
+ GPIO_PTS0, GPIO_PTS1, GPIO_PTS2, GPIO_PTS3,
+ GPIO_PTS4, GPIO_PTS5, GPIO_PTS6, GPIO_PTS7,
/* PTT */
- GPIO_PTT5, GPIO_PTT4,
- GPIO_PTT3, GPIO_PTT2, GPIO_PTT1, GPIO_PTT0,
+ GPIO_PTT0, GPIO_PTT1, GPIO_PTT2, GPIO_PTT3,
+ GPIO_PTT4, GPIO_PTT5, GPIO_PTT6, GPIO_PTT7,
/* PTU */
- GPIO_PTU7, GPIO_PTU6, GPIO_PTU5, GPIO_PTU4,
- GPIO_PTU3, GPIO_PTU2, GPIO_PTU1, GPIO_PTU0,
+ GPIO_PTU0, GPIO_PTU1, GPIO_PTU2, GPIO_PTU3,
+ GPIO_PTU4, GPIO_PTU5, GPIO_PTU6, GPIO_PTU7,
/* PTV */
- GPIO_PTV7, GPIO_PTV6, GPIO_PTV5, GPIO_PTV4,
- GPIO_PTV3, GPIO_PTV2, GPIO_PTV1, GPIO_PTV0,
+ GPIO_PTV0, GPIO_PTV1, GPIO_PTV2, GPIO_PTV3,
+ GPIO_PTV4, GPIO_PTV5, GPIO_PTV6, GPIO_PTV7,
/* PTW */
- GPIO_PTW7, GPIO_PTW6, GPIO_PTW5, GPIO_PTW4,
- GPIO_PTW3, GPIO_PTW2, GPIO_PTW1, GPIO_PTW0,
+ GPIO_PTW0, GPIO_PTW1, GPIO_PTW2, GPIO_PTW3,
+ GPIO_PTW4, GPIO_PTW5, GPIO_PTW6, GPIO_PTW7,
/* PTX */
- GPIO_PTX7, GPIO_PTX6, GPIO_PTX5, GPIO_PTX4,
- GPIO_PTX3, GPIO_PTX2, GPIO_PTX1, GPIO_PTX0,
+ GPIO_PTX0, GPIO_PTX1, GPIO_PTX2, GPIO_PTX3,
+ GPIO_PTX4, GPIO_PTX5, GPIO_PTX6, GPIO_PTX7,
/* PTY */
- GPIO_PTY7, GPIO_PTY6, GPIO_PTY5, GPIO_PTY4,
- GPIO_PTY3, GPIO_PTY2, GPIO_PTY1, GPIO_PTY0,
+ GPIO_PTY0, GPIO_PTY1, GPIO_PTY2, GPIO_PTY3,
+ GPIO_PTY4, GPIO_PTY5, GPIO_PTY6, GPIO_PTY7,
/* PTZ */
- GPIO_PTZ7, GPIO_PTZ6, GPIO_PTZ5, GPIO_PTZ4,
- GPIO_PTZ3, GPIO_PTZ2, GPIO_PTZ1, GPIO_PTZ0,
+ GPIO_PTZ0, GPIO_PTZ1, GPIO_PTZ2, GPIO_PTZ3,
+ GPIO_PTZ4, GPIO_PTZ5, GPIO_PTZ6, GPIO_PTZ7,
- /* PTA (mobule: LBSC, CPG, LPC) */
+ /* PTA (mobule: LBSC, RGMII) */
GPIO_FN_BS, GPIO_FN_RDWR, GPIO_FN_WE1, GPIO_FN_RDY,
- GPIO_FN_MD10, GPIO_FN_MD9, GPIO_FN_MD8,
- GPIO_FN_LGPIO7, GPIO_FN_LGPIO6, GPIO_FN_LGPIO5, GPIO_FN_LGPIO4,
- GPIO_FN_LGPIO3, GPIO_FN_LGPIO2, GPIO_FN_LGPIO1, GPIO_FN_LGPIO0,
-
- /* PTB (mobule: LBSC, EtherC, SIM, LPC) */
- GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
- GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9, GPIO_FN_D8,
- GPIO_FN_ET0_MDC, GPIO_FN_ET0_MDIO,
- GPIO_FN_ET1_MDC, GPIO_FN_ET1_MDIO,
- GPIO_FN_SIM_D, GPIO_FN_SIM_CLK, GPIO_FN_SIM_RST,
- GPIO_FN_WPSZ1, GPIO_FN_WPSZ0, GPIO_FN_FWID, GPIO_FN_FLSHSZ,
- GPIO_FN_LPC_SPIEN, GPIO_FN_BASEL,
+ GPIO_FN_ET0_MDC, GPIO_FN_ET0_MDIO,
+ GPIO_FN_ET1_MDC, GPIO_FN_ET1_MDIO,
- /* PTC (mobule: SD) */
- GPIO_FN_SD_WP, GPIO_FN_SD_CD, GPIO_FN_SD_CLK, GPIO_FN_SD_CMD,
- GPIO_FN_SD_D3, GPIO_FN_SD_D2, GPIO_FN_SD_D1, GPIO_FN_SD_D0,
+ /* PTB (mobule: INTC, ONFI, TMU) */
+ GPIO_FN_IRQ15, GPIO_FN_IRQ14, GPIO_FN_IRQ13, GPIO_FN_IRQ12,
+ GPIO_FN_IRQ11, GPIO_FN_IRQ10, GPIO_FN_IRQ9, GPIO_FN_IRQ8,
+ GPIO_FN_ON_NRE, GPIO_FN_ON_NWE, GPIO_FN_ON_NWP, GPIO_FN_ON_NCE0,
+ GPIO_FN_ON_R_B0, GPIO_FN_ON_ALE, GPIO_FN_ON_CLE,
+ GPIO_FN_TCLK,
- /* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+ /* PTC (mobule: IRQ, PWMU) */
GPIO_FN_IRQ7, GPIO_FN_IRQ6, GPIO_FN_IRQ5, GPIO_FN_IRQ4,
GPIO_FN_IRQ3, GPIO_FN_IRQ2, GPIO_FN_IRQ1, GPIO_FN_IRQ0,
- GPIO_FN_MD6, GPIO_FN_MD5, GPIO_FN_MD3, GPIO_FN_MD2,
- GPIO_FN_MD1, GPIO_FN_MD0, GPIO_FN_ADTRG1, GPIO_FN_ADTRG0,
-
- /* PTE (mobule: EtherC) */
- GPIO_FN_ET0_CRS_DV, GPIO_FN_ET0_TXD1,
- GPIO_FN_ET0_TXD0, GPIO_FN_ET0_TX_EN,
- GPIO_FN_ET0_REF_CLK, GPIO_FN_ET0_RXD1,
- GPIO_FN_ET0_RXD0, GPIO_FN_ET0_RX_ER,
-
- /* PTF (mobule: EtherC) */
- GPIO_FN_ET1_CRS_DV, GPIO_FN_ET1_TXD1,
- GPIO_FN_ET1_TXD0, GPIO_FN_ET1_TX_EN,
- GPIO_FN_ET1_REF_CLK, GPIO_FN_ET1_RXD1,
- GPIO_FN_ET1_RXD0, GPIO_FN_ET1_RX_ER,
-
- /* PTG (mobule: SYSTEM, PWMX, LPC) */
- GPIO_FN_STATUS0, GPIO_FN_STATUS1,
- GPIO_FN_PWX0, GPIO_FN_PWX1, GPIO_FN_PWX2, GPIO_FN_PWX3,
- GPIO_FN_SERIRQ, GPIO_FN_CLKRUN, GPIO_FN_LPCPD, GPIO_FN_LDRQ,
-
- /* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
- GPIO_FN_TCLK, GPIO_FN_RXD4, GPIO_FN_TXD4,
+ GPIO_FN_PWMU0, GPIO_FN_PWMU1, GPIO_FN_PWMU2, GPIO_FN_PWMU3,
+ GPIO_FN_PWMU4, GPIO_FN_PWMU5,
+
+ /* PTD (mobule: SPI0, DMAC) */
+ GPIO_FN_SP0_MOSI, GPIO_FN_SP0_MISO, GPIO_FN_SP0_SCK,
+ GPIO_FN_SP0_SCK_FB, GPIO_FN_SP0_SS0, GPIO_FN_SP0_SS1,
+ GPIO_FN_SP0_SS2, GPIO_FN_SP0_SS3, GPIO_FN_DREQ0,
+ GPIO_FN_DACK0, GPIO_FN_TEND0,
+
+ /* PTE (mobule: RMII) */
+ GPIO_FN_RMII0_CRS_DV, GPIO_FN_RMII0_TXD1, GPIO_FN_RMII0_TXD0,
+ GPIO_FN_RMII0_TXEN, GPIO_FN_RMII0_REFCLK, GPIO_FN_RMII0_RXD1,
+ GPIO_FN_RMII0_RXD0, GPIO_FN_RMII0_RX_ER,
+
+ /* PTF (mobule: RMII, SerMux) */
+ GPIO_FN_RMII1_CRS_DV, GPIO_FN_RMII1_TXD1, GPIO_FN_RMII1_TXD0,
+ GPIO_FN_RMII1_TXEN, GPIO_FN_RMII1_REFCLK, GPIO_FN_RMII1_RXD1,
+ GPIO_FN_RMII1_RXD0, GPIO_FN_RMII1_RX_ER, GPIO_FN_RAC_RI,
+
+ /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+ GPIO_FN_BOOTFMS, GPIO_FN_BOOTWP,
+ GPIO_FN_A25, GPIO_FN_A24, GPIO_FN_SERIRQ, GPIO_FN_WDTOVF,
+ GPIO_FN_LPCPD, GPIO_FN_LDRQ, GPIO_FN_MMCCLK, GPIO_FN_MMCCMD,
+
+ /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
GPIO_FN_SP1_MOSI, GPIO_FN_SP1_MISO,
GPIO_FN_SP1_SCK, GPIO_FN_SP1_SCK_FB,
GPIO_FN_SP1_SS0, GPIO_FN_SP1_SS1,
- GPIO_FN_SP0_SS1,
-
- /* PTI (mobule: INTC) */
- GPIO_FN_IRQ15, GPIO_FN_IRQ14, GPIO_FN_IRQ13, GPIO_FN_IRQ12,
- GPIO_FN_IRQ11, GPIO_FN_IRQ10, GPIO_FN_IRQ9, GPIO_FN_IRQ8,
-
- /* PTJ (mobule: SCIF234, SERMUX) */
- GPIO_FN_RXD3, GPIO_FN_TXD3, GPIO_FN_RXD2, GPIO_FN_TXD2,
- GPIO_FN_COM1_TXD, GPIO_FN_COM1_RXD,
- GPIO_FN_COM1_RTS, GPIO_FN_COM1_CTS,
-
- /* PTK (mobule: SERMUX) */
- GPIO_FN_COM2_TXD, GPIO_FN_COM2_RXD,
- GPIO_FN_COM2_RTS, GPIO_FN_COM2_CTS,
- GPIO_FN_COM2_DTR, GPIO_FN_COM2_DSR,
- GPIO_FN_COM2_DCD, GPIO_FN_COM2_RI,
+ GPIO_FN_WP, GPIO_FN_FMS0, GPIO_FN_TEND1, GPIO_FN_DREQ1,
+ GPIO_FN_DACK1, GPIO_FN_ADTRG1, GPIO_FN_ADTRG0,
- /* PTL (mobule: SERMUX) */
- GPIO_FN_RAC_TXD, GPIO_FN_RAC_RXD,
- GPIO_FN_RAC_RTS, GPIO_FN_RAC_CTS,
- GPIO_FN_RAC_DTR, GPIO_FN_RAC_DSR,
- GPIO_FN_RAC_DCD, GPIO_FN_RAC_RI,
+ /* PTI (mobule: LBSC, SDHI) */
+ GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
+ GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9, GPIO_FN_D8,
+ GPIO_FN_SD_WP, GPIO_FN_SD_CD, GPIO_FN_SD_CLK, GPIO_FN_SD_CMD,
+ GPIO_FN_SD_D3, GPIO_FN_SD_D2, GPIO_FN_SD_D1, GPIO_FN_SD_D0,
- /* PTM (mobule: IIC, LPC) */
+ /* PTJ (mobule: SCIF234) */
+ GPIO_FN_RTS3, GPIO_FN_CTS3, GPIO_FN_TXD3, GPIO_FN_RXD3,
+ GPIO_FN_RTS4, GPIO_FN_RXD4, GPIO_FN_TXD4,
+
+ /* PTK (mobule: SERMUX, LBSC, SCIF) */
+ GPIO_FN_COM2_TXD, GPIO_FN_COM2_RXD, GPIO_FN_COM2_RTS,
+ GPIO_FN_COM2_CTS, GPIO_FN_COM2_DTR, GPIO_FN_COM2_DSR,
+ GPIO_FN_COM2_DCD, GPIO_FN_CLKOUT,
+ GPIO_FN_SCK2, GPIO_FN_SCK4, GPIO_FN_SCK3,
+
+ /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
+ GPIO_FN_RAC_RXD, GPIO_FN_RAC_RTS, GPIO_FN_RAC_CTS,
+ GPIO_FN_RAC_DTR, GPIO_FN_RAC_DSR, GPIO_FN_RAC_DCD,
+ GPIO_FN_RAC_TXD, GPIO_FN_RXD2, GPIO_FN_CS5,
+ GPIO_FN_CS6, GPIO_FN_AUDSYNC, GPIO_FN_AUDCK,
+ GPIO_FN_TXD2,
+
+ /* PTM (mobule: LBSC, IIC) */
+ GPIO_FN_CS4, GPIO_FN_RD, GPIO_FN_WE0, GPIO_FN_CS0,
GPIO_FN_SDA6, GPIO_FN_SCL6, GPIO_FN_SDA7, GPIO_FN_SCL7,
- GPIO_FN_WP, GPIO_FN_FMS0, GPIO_FN_FMS1,
-
- /* PTN (mobule: SCIF234, EVC) */
- GPIO_FN_SCK2, GPIO_FN_RTS4, GPIO_FN_RTS3, GPIO_FN_RTS2,
- GPIO_FN_CTS4, GPIO_FN_CTS3, GPIO_FN_CTS2,
- GPIO_FN_EVENT7, GPIO_FN_EVENT6, GPIO_FN_EVENT5, GPIO_FN_EVENT4,
- GPIO_FN_EVENT3, GPIO_FN_EVENT2, GPIO_FN_EVENT1, GPIO_FN_EVENT0,
- /* PTO (mobule: SGPIO) */
- GPIO_FN_SGPIO0_CLK, GPIO_FN_SGPIO0_LOAD,
- GPIO_FN_SGPIO0_DI, GPIO_FN_SGPIO0_DO,
- GPIO_FN_SGPIO1_CLK, GPIO_FN_SGPIO1_LOAD,
- GPIO_FN_SGPIO1_DI, GPIO_FN_SGPIO1_DO,
+ /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+ GPIO_FN_VBUS_EN, GPIO_FN_VBUS_OC, GPIO_FN_JMCTCK,
+ GPIO_FN_JMCTMS, GPIO_FN_JMCTDO, GPIO_FN_JMCTDI,
+ GPIO_FN_JMCTRST,
+ GPIO_FN_SGPIO1_CLK, GPIO_FN_SGPIO1_LOAD, GPIO_FN_SGPIO1_DI,
+ GPIO_FN_SGPIO1_DO, GPIO_FN_SUB_CLKIN,
- /* PTP (mobule: JMC, SCIF234) */
- GPIO_FN_JMCTCK, GPIO_FN_JMCTMS, GPIO_FN_JMCTDO, GPIO_FN_JMCTDI,
- GPIO_FN_JMCRST, GPIO_FN_SCK4, GPIO_FN_SCK3,
+ /* PTO (mobule: SGPIO, SerMux) */
+ GPIO_FN_SGPIO0_CLK, GPIO_FN_SGPIO0_LOAD, GPIO_FN_SGPIO0_DI,
+ GPIO_FN_SGPIO0_DO, GPIO_FN_SGPIO2_CLK, GPIO_FN_SGPIO2_LOAD,
+ GPIO_FN_SGPIO2_DI, GPIO_FN_SGPIO2_DO, GPIO_FN_COM1_TXD,
+ GPIO_FN_COM1_RXD, GPIO_FN_COM1_RTS, GPIO_FN_COM1_CTS,
/* PTQ (mobule: LPC) */
GPIO_FN_LAD3, GPIO_FN_LAD2, GPIO_FN_LAD1, GPIO_FN_LAD0,
GPIO_FN_LFRAME, GPIO_FN_LRESET, GPIO_FN_LCLK,
/* PTR (mobule: GRA, IIC) */
- GPIO_FN_DDC3, GPIO_FN_DDC2,
- GPIO_FN_SDA8, GPIO_FN_SCL8, GPIO_FN_SDA2, GPIO_FN_SCL2,
+ GPIO_FN_DDC3, GPIO_FN_DDC2, GPIO_FN_SDA2, GPIO_FN_SCL2,
GPIO_FN_SDA1, GPIO_FN_SCL1, GPIO_FN_SDA0, GPIO_FN_SCL0,
+ GPIO_FN_SDA8, GPIO_FN_SCL8,
/* PTS (mobule: GRA, IIC) */
- GPIO_FN_DDC1, GPIO_FN_DDC0,
- GPIO_FN_SDA9, GPIO_FN_SCL9, GPIO_FN_SDA5, GPIO_FN_SCL5,
+ GPIO_FN_DDC1, GPIO_FN_DDC0, GPIO_FN_SDA5, GPIO_FN_SCL5,
GPIO_FN_SDA4, GPIO_FN_SCL4, GPIO_FN_SDA3, GPIO_FN_SCL3,
+ GPIO_FN_SDA9, GPIO_FN_SCL9,
- /* PTT (mobule: SYSTEM, PWMX) */
- GPIO_FN_AUDSYNC, GPIO_FN_AUDCK,
- GPIO_FN_AUDATA3, GPIO_FN_AUDATA2,
- GPIO_FN_AUDATA1, GPIO_FN_AUDATA0,
- GPIO_FN_PWX7, GPIO_FN_PWX6, GPIO_FN_PWX5, GPIO_FN_PWX4,
+ /* PTT (mobule: PWMX, AUD) */
+ GPIO_FN_PWMX7, GPIO_FN_PWMX6, GPIO_FN_PWMX5, GPIO_FN_PWMX4,
+ GPIO_FN_PWMX3, GPIO_FN_PWMX2, GPIO_FN_PWMX1, GPIO_FN_PWMX0,
+ GPIO_FN_AUDATA3, GPIO_FN_AUDATA2, GPIO_FN_AUDATA1,
+ GPIO_FN_AUDATA0, GPIO_FN_STATUS1, GPIO_FN_STATUS0,
- /* PTU (mobule: LBSC, DMAC) */
- GPIO_FN_CS6, GPIO_FN_CS5, GPIO_FN_CS4, GPIO_FN_CS0,
- GPIO_FN_RD, GPIO_FN_WE0, GPIO_FN_A25, GPIO_FN_A24,
- GPIO_FN_DREQ0, GPIO_FN_DACK0,
+ /* PTU (mobule: LPC, APM) */
+ GPIO_FN_LGPIO7, GPIO_FN_LGPIO6, GPIO_FN_LGPIO5, GPIO_FN_LGPIO4,
+ GPIO_FN_LGPIO3, GPIO_FN_LGPIO2, GPIO_FN_LGPIO1, GPIO_FN_LGPIO0,
+ GPIO_FN_APMONCTL_O, GPIO_FN_APMPWBTOUT_O, GPIO_FN_APMSCI_O,
+ GPIO_FN_APMVDDON, GPIO_FN_APMSLPBTN, GPIO_FN_APMPWRBTN,
+ GPIO_FN_APMS5N, GPIO_FN_APMS3N,
- /* PTV (mobule: LBSC, DMAC) */
+ /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
GPIO_FN_A23, GPIO_FN_A22, GPIO_FN_A21, GPIO_FN_A20,
GPIO_FN_A19, GPIO_FN_A18, GPIO_FN_A17, GPIO_FN_A16,
- GPIO_FN_TEND0, GPIO_FN_DREQ1, GPIO_FN_DACK1, GPIO_FN_TEND1,
+ GPIO_FN_COM2_RI, GPIO_FN_R_SPI_MOSI, GPIO_FN_R_SPI_MISO,
+ GPIO_FN_R_SPI_RSPCK, GPIO_FN_R_SPI_SSL0, GPIO_FN_R_SPI_SSL1,
+ GPIO_FN_EVENT7, GPIO_FN_EVENT6, GPIO_FN_VBIOS_DI,
+ GPIO_FN_VBIOS_DO, GPIO_FN_VBIOS_CLK, GPIO_FN_VBIOS_CS,
- /* PTW (mobule: LBSC) */
+ /* PTW (mobule: LBSC, EVC, SCIF) */
GPIO_FN_A15, GPIO_FN_A14, GPIO_FN_A13, GPIO_FN_A12,
GPIO_FN_A11, GPIO_FN_A10, GPIO_FN_A9, GPIO_FN_A8,
+ GPIO_FN_EVENT5, GPIO_FN_EVENT4, GPIO_FN_EVENT3, GPIO_FN_EVENT2,
+ GPIO_FN_EVENT1, GPIO_FN_EVENT0, GPIO_FN_CTS4, GPIO_FN_CTS2,
- /* PTX (mobule: LBSC) */
+ /* PTX (mobule: LBSC, SCIF, SIM) */
GPIO_FN_A7, GPIO_FN_A6, GPIO_FN_A5, GPIO_FN_A4,
GPIO_FN_A3, GPIO_FN_A2, GPIO_FN_A1, GPIO_FN_A0,
+ GPIO_FN_RTS2, GPIO_FN_SIM_D, GPIO_FN_SIM_CLK, GPIO_FN_SIM_RST,
/* PTY (mobule: LBSC) */
GPIO_FN_D7, GPIO_FN_D6, GPIO_FN_D5, GPIO_FN_D4,
GPIO_FN_D3, GPIO_FN_D2, GPIO_FN_D1, GPIO_FN_D0,
+
+ /* PTZ (mobule: eMMC, ONFI) */
+ GPIO_FN_MMCDAT7, GPIO_FN_MMCDAT6, GPIO_FN_MMCDAT5,
+ GPIO_FN_MMCDAT4, GPIO_FN_MMCDAT3, GPIO_FN_MMCDAT2,
+ GPIO_FN_MMCDAT1, GPIO_FN_MMCDAT0,
+ GPIO_FN_ON_DQ7, GPIO_FN_ON_DQ6, GPIO_FN_ON_DQ5, GPIO_FN_ON_DQ4,
+ GPIO_FN_ON_DQ3, GPIO_FN_ON_DQ2, GPIO_FN_ON_DQ1, GPIO_FN_ON_DQ0,
};
#endif /* __ASM_SH7757_H__ */
diff --git a/arch/sh/include/cpu-sh4/cpu/shx3.h b/arch/sh/include/cpu-sh4/cpu/shx3.h
new file mode 100644
index 000000000000..68d9080a8da9
--- /dev/null
+++ b/arch/sh/include/cpu-sh4/cpu/shx3.h
@@ -0,0 +1,64 @@
+#ifndef __CPU_SHX3_H
+#define __CPU_SHX3_H
+
+enum {
+ /* PA */
+ GPIO_PA7, GPIO_PA6, GPIO_PA5, GPIO_PA4,
+ GPIO_PA3, GPIO_PA2, GPIO_PA1, GPIO_PA0,
+
+ /* PB */
+ GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+ GPIO_PB3, GPIO_PB2, GPIO_PB1, GPIO_PB0,
+
+ /* PC */
+ GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+ GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+ /* PD */
+ GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+ GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+ /* PE */
+ GPIO_PE7, GPIO_PE6, GPIO_PE5, GPIO_PE4,
+ GPIO_PE3, GPIO_PE2, GPIO_PE1, GPIO_PE0,
+
+ /* PF */
+ GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+ GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+ /* PG */
+ GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+ GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+ /* PH */
+ GPIO_PH5, GPIO_PH4,
+ GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+ /* SCIF */
+ GPIO_FN_SCK3, GPIO_FN_TXD3, GPIO_FN_RXD3,
+ GPIO_FN_SCK2, GPIO_FN_TXD2, GPIO_FN_RXD2,
+ GPIO_FN_SCK1, GPIO_FN_TXD1, GPIO_FN_RXD1,
+ GPIO_FN_SCK0, GPIO_FN_TXD0, GPIO_FN_RXD0,
+
+ /* LBSC */
+ GPIO_FN_D31, GPIO_FN_D30, GPIO_FN_D29, GPIO_FN_D28,
+ GPIO_FN_D27, GPIO_FN_D26, GPIO_FN_D25, GPIO_FN_D24,
+ GPIO_FN_D23, GPIO_FN_D22, GPIO_FN_D21, GPIO_FN_D20,
+ GPIO_FN_D19, GPIO_FN_D18, GPIO_FN_D17, GPIO_FN_D16,
+ GPIO_FN_WE3, GPIO_FN_WE2, GPIO_FN_CS6, GPIO_FN_CS5,
+ GPIO_FN_CS4, GPIO_FN_CLKOUTENB, GPIO_FN_BREQ,
+ GPIO_FN_IOIS16, GPIO_FN_CE2B, GPIO_FN_CE2A, GPIO_FN_BACK,
+
+ /* DMAC */
+ GPIO_FN_DACK0, GPIO_FN_DREQ0, GPIO_FN_DRAK0,
+ GPIO_FN_DACK1, GPIO_FN_DREQ1, GPIO_FN_DRAK1,
+ GPIO_FN_DACK2, GPIO_FN_DREQ2, GPIO_FN_DRAK2,
+ GPIO_FN_DACK3, GPIO_FN_DREQ3, GPIO_FN_DRAK3,
+
+ /* INTC */
+ GPIO_FN_IRQ3, GPIO_FN_IRQ2, GPIO_FN_IRQ1, GPIO_FN_IRQ0,
+ GPIO_FN_IRL3, GPIO_FN_IRL2, GPIO_FN_IRL1, GPIO_FN_IRL0,
+ GPIO_FN_IRQOUT, GPIO_FN_STATUS1, GPIO_FN_STATUS0,
+};
+
+#endif /* __CPU_SHX3_H */
diff --git a/arch/sh/include/mach-common/mach/sh2007.h b/arch/sh/include/mach-common/mach/sh2007.h
new file mode 100644
index 000000000000..48180b9aa03d
--- /dev/null
+++ b/arch/sh/include/mach-common/mach/sh2007.h
@@ -0,0 +1,117 @@
+#ifndef __MACH_SH2007_H
+#define __MACH_SH2007_H
+
+#define CS5BCR 0xff802050
+#define CS5WCR 0xff802058
+#define CS5PCR 0xff802070
+
+#define BUS_SZ8 1
+#define BUS_SZ16 2
+#define BUS_SZ32 3
+
+#define PCMCIA_IODYN 1
+#define PCMCIA_ATA 0
+#define PCMCIA_IO8 2
+#define PCMCIA_IO16 3
+#define PCMCIA_COMM8 4
+#define PCMCIA_COMM16 5
+#define PCMCIA_ATTR8 6
+#define PCMCIA_ATTR16 7
+
+#define TYPE_SRAM 0
+#define TYPE_PCMCIA 4
+
+/* write-read/write-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWW5 0
+#define IWW6 3
+/* different area, read-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRWD5 2
+#define IWRWD6 2
+/* same area, read-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRWS5 2
+#define IWRWS6 2
+/* different area, read-read delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRRD5 2
+#define IWRRD6 2
+/* same area, read-read delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRRS5 0
+#define IWRRS6 2
+/* burst count (0-3:4,8,16,32) */
+#define BST5 0
+#define BST6 0
+/* bus size */
+#define SZ5 BUS_SZ16
+#define SZ6 BUS_SZ16
+/* RD hold for SRAM (0-1:0,1) */
+#define RDSPL5 0
+#define RDSPL6 0
+/* Burst pitch (0-7:0,1,2,3,4,5,6,7) */
+#define BW5 0
+#define BW6 0
+/* Multiplex (0-1:0,1) */
+#define MPX5 0
+#define MPX6 0
+/* device type */
+#define TYPE5 TYPE_PCMCIA
+#define TYPE6 TYPE_PCMCIA
+/* address setup before assert CSn for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define ADS5 0
+#define ADS6 0
+/* address hold after negate CSn for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define ADH5 0
+#define ADH6 0
+/* CSn assert to RD assert delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define RDS5 0
+#define RDS6 0
+/* RD negate to CSn negate delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define RDH5 0
+#define RDH6 0
+/* CSn assert to WE assert delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define WTS5 0
+#define WTS6 0
+/* WE negate to CSn negate delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define WTH5 0
+#define WTH6 0
+/* BS hold (0-1:1,2) */
+#define BSH5 0
+#define BSH6 0
+/* wait cycle (0-15:0,1,2,3,4,5,6,7,8,9,11,13,15,17,21,25) */
+#define IW5 6 /* 60ns PIO mode 4 */
+#define IW6 15 /* 250ns */
+
+#define SAA5 PCMCIA_IODYN /* IDE area b4000000-b5ffffff */
+#define SAB5 PCMCIA_IODYN /* CF area b6000000-b7ffffff */
+#define PCWA5 0 /* additional wait A (0-3:0,15,30,50) */
+#define PCWB5 0 /* additional wait B (0-3:0,15,30,50) */
+/* wait B (0-15:0,1,2,3,4,5,6,7,8,9,11,13,15,17,21,25) */
+#define PCIW5 12
+/* Address->OE/WE assert delay A (0-7:0,1,2,3,6,9,12,15) */
+#define TEDA5 2
+/* Address->OE/WE assert delay B (0-7:0,1,2,3,6,9,12,15) */
+#define TEDB5 4
+/* OE/WE negate->Address delay A (0-7:0,1,2,3,6,9,12,15) */
+#define TEHA5 2
+/* OE/WE negate->Address delay B (0-7:0,1,2,3,6,9,12,15) */
+#define TEHB5 3
+
+#define CS5BCR_D ((IWW5<<28)|(IWRWD5<<24)|(IWRWS5<<20)| \
+ (IWRRD5<<16)|(IWRRS5<<12)|(BST5<<10)| \
+ (SZ5<<8)|(RDSPL5<<7)|(BW5<<4)|(MPX5<<3)|TYPE5)
+#define CS5WCR_D ((ADS5<<28)|(ADH5<<24)|(RDS5<<20)| \
+ (RDH5<<16)|(WTS5<<12)|(WTH5<<8)|(BSH5<<4)|IW5)
+#define CS5PCR_D ((SAA5<<28)|(SAB5<<24)|(PCWA5<<22)| \
+ (PCWB5<<20)|(PCIW5<<16)|(TEDA5<<12)| \
+ (TEDB5<<8)|(TEHA5<<4)|TEHB5)
+
+#define SMC0_BASE 0xb0800000 /* eth0 */
+#define SMC1_BASE 0xb0900000 /* eth1 */
+#define CF_BASE 0xb6100000 /* Compact Flash (I/O area) */
+#define IDE_BASE 0xb4000000 /* IDE */
+#define PC104_IO_BASE 0xb8000000
+#define PC104_MEM_BASE 0xba000000
+#define SMC_IO_SIZE 0x100
+
+#define CF_OFFSET 0x1f0
+#define IDE_OFFSET 0x170
+
+#endif /* __MACH_SH2007_H */
diff --git a/arch/sh/include/mach-sdk7786/mach/fpga.h b/arch/sh/include/mach-sdk7786/mach/fpga.h
index 416b621d94d1..40f0c2d3690c 100644
--- a/arch/sh/include/mach-sdk7786/mach/fpga.h
+++ b/arch/sh/include/mach-sdk7786/mach/fpga.h
@@ -31,11 +31,35 @@
#define EXTASR 0x110
#define SPCAR 0x120
#define INTMSR 0x130
+
#define PCIECR 0x140
+#define PCIECR_PCIEMUX1 BIT(15)
+#define PCIECR_PCIEMUX0 BIT(14)
+#define PCIECR_PRST4 BIT(12) /* slot 4 card present */
+#define PCIECR_PRST3 BIT(11) /* slot 3 card present */
+#define PCIECR_PRST2 BIT(10) /* slot 2 card present */
+#define PCIECR_PRST1 BIT(9) /* slot 1 card present */
+#define PCIECR_CLKEN BIT(4) /* oscillator enable */
+
#define FAER 0x150
#define USRGPIR 0x160
+
/* 0x170 reserved */
-#define LCLASR 0x180
+
+#define LCLASR 0x180
+#define LCLASR_FRAMEN BIT(15)
+
+#define LCLASR_FPGA_SEL_SHIFT 12
+#define LCLASR_NAND_SEL_SHIFT 8
+#define LCLASR_NORB_SEL_SHIFT 4
+#define LCLASR_NORA_SEL_SHIFT 0
+
+#define LCLASR_AREA_MASK 0x7
+
+#define LCLASR_FPGA_SEL_MASK (LCLASR_AREA_MASK << LCLASR_FPGA_SEL_SHIFT)
+#define LCLASR_NAND_SEL_MASK (LCLASR_AREA_MASK << LCLASR_NAND_SEL_SHIFT)
+#define LCLASR_NORB_SEL_MASK (LCLASR_AREA_MASK << LCLASR_NORB_SEL_SHIFT)
+#define LCLASR_NORA_SEL_MASK (LCLASR_AREA_MASK << LCLASR_NORA_SEL_SHIFT)
#define SBCR 0x190
#define SCBR_I2CMEN BIT(0) /* FPGA I2C master enable */
diff --git a/arch/sh/include/mach-x3proto/mach/hardware.h b/arch/sh/include/mach-x3proto/mach/hardware.h
new file mode 100644
index 000000000000..52bca57bfeb6
--- /dev/null
+++ b/arch/sh/include/mach-x3proto/mach/hardware.h
@@ -0,0 +1,12 @@
+#ifndef __MACH_X3PROTO_HARDWARE_H
+#define __MACH_X3PROTO_HARDWARE_H
+
+struct gpio_chip;
+
+/* arch/sh/boards/mach-x3proto/gpio.c */
+int x3proto_gpio_setup(void);
+extern struct gpio_chip x3proto_gpio_chip;
+
+#define NR_BASEBOARD_GPIOS 16
+
+#endif /* __MACH_X3PROTO_HARDWARE_H */
diff --git a/arch/sh/include/asm/ilsel.h b/arch/sh/include/mach-x3proto/mach/ilsel.h
index e3d304b280f6..e3d304b280f6 100644
--- a/arch/sh/include/asm/ilsel.h
+++ b/arch/sh/include/mach-x3proto/mach/ilsel.h
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index e25f3c69525d..8eed6a485446 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -12,9 +12,9 @@ endif
CFLAGS_REMOVE_return_address.o = -pg
obj-y := clkdev.o debugtraps.o dma-nommu.o dumpstack.o \
- idle.o io.o irq.o \
- irq_$(BITS).o machvec.o nmi_debug.o process.o \
- process_$(BITS).o ptrace_$(BITS).o \
+ idle.o io.o irq.o irq_$(BITS).o kdebugfs.o \
+ machvec.o nmi_debug.o process.o \
+ process_$(BITS).o ptrace.o ptrace_$(BITS).o \
reboot.o return_address.o \
setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \
syscalls_$(BITS).o time.o topology.o traps.o \
@@ -44,4 +44,4 @@ obj-$(CONFIG_HAS_IOPORT) += io_generic.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff --git a/arch/sh/kernel/clkdev.c b/arch/sh/kernel/clkdev.c
index befc255830a4..1f800ef4a735 100644
--- a/arch/sh/kernel/clkdev.c
+++ b/arch/sh/kernel/clkdev.c
@@ -161,9 +161,11 @@ EXPORT_SYMBOL(clk_add_alias);
*/
void clkdev_drop(struct clk_lookup *cl)
{
+ struct clk_lookup_alloc *cla = container_of(cl, struct clk_lookup_alloc, cl);
+
mutex_lock(&clocks_mutex);
list_del(&cl->node);
mutex_unlock(&clocks_mutex);
- kfree(cl);
+ kfree(cla);
}
EXPORT_SYMBOL(clkdev_drop);
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index d180f16281ed..b93458f33b74 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -150,7 +150,7 @@ void __cpuinit cpu_probe(void)
boot_cpu_data.type = CPU_SH7724;
boot_cpu_data.flags |= CPU_HAS_L2_CACHE;
break;
- case 0x50:
+ case 0x10:
boot_cpu_data.type = CPU_SH7757;
break;
}
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index b144e8af89dc..cc122b1d3035 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -8,13 +8,13 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7763) += setup-sh7763.o
obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7786) += setup-sh7786.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7786) += setup-sh7786.o intc-shx3.o
obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
obj-$(CONFIG_CPU_SUBTYPE_SH7723) += setup-sh7723.o
obj-$(CONFIG_CPU_SUBTYPE_SH7724) += setup-sh7724.o
obj-$(CONFIG_CPU_SUBTYPE_SH7366) += setup-sh7366.o
-obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o
+obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o intc-shx3.o
# SMP setup
smp-$(CONFIG_CPU_SHX3) := smp-shx3.o
@@ -40,6 +40,7 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7724) := pinmux-sh7724.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7757) := pinmux-sh7757.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7785) := pinmux-sh7785.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SHX3) := pinmux-shx3.o
obj-y += $(clock-y)
obj-$(CONFIG_SMP) += $(smp-y)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
index 0a752bd324ac..ce39a2ae8c6c 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
@@ -3,7 +3,7 @@
*
* SH7757 support for the clock framework
*
- * Copyright (C) 2009 Renesas Solutions Corp.
+ * Copyright (C) 2009-2010 Renesas Solutions Corp.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -16,124 +16,147 @@
#include <asm/clock.h>
#include <asm/freq.h>
-static int ifc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
- 16, 1, 1, 32, 1, 1, 1, 1 };
-static int sfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
- 16, 1, 1, 32, 1, 1, 1, 1 };
-static int bfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
- 16, 1, 1, 32, 1, 1, 1, 1 };
-static int p1fc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
- 16, 1, 1, 32, 1, 1, 1, 1 };
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+ .rate = 48000000,
+};
-static void master_clk_init(struct clk *clk)
+static unsigned long pll_recalc(struct clk *clk)
{
- clk->rate = CONFIG_SH_PCLK_FREQ * 16;
-}
+ int multiplier;
-static struct clk_ops sh7757_master_clk_ops = {
- .init = master_clk_init,
-};
+ multiplier = test_mode_pin(MODE_PIN0) ? 24 : 16;
-static void module_clk_recalc(struct clk *clk)
-{
- int idx = __raw_readl(FRQCR) & 0x0000000f;
- clk->rate = clk->parent->rate / p1fc_divisors[idx];
+ return clk->parent->rate * multiplier;
}
-static struct clk_ops sh7757_module_clk_ops = {
- .recalc = module_clk_recalc,
+static struct clk_ops pll_clk_ops = {
+ .recalc = pll_recalc,
};
-static void bus_clk_recalc(struct clk *clk)
-{
- int idx = (__raw_readl(FRQCR) >> 8) & 0x0000000f;
- clk->rate = clk->parent->rate / bfc_divisors[idx];
-}
+static struct clk pll_clk = {
+ .ops = &pll_clk_ops,
+ .parent = &extal_clk,
+ .flags = CLK_ENABLE_ON_INIT,
+};
-static struct clk_ops sh7757_bus_clk_ops = {
- .recalc = bus_clk_recalc,
+static struct clk *clks[] = {
+ &extal_clk,
+ &pll_clk,
};
-static void cpu_clk_recalc(struct clk *clk)
-{
- int idx = (__raw_readl(FRQCR) >> 20) & 0x0000000f;
- clk->rate = clk->parent->rate / ifc_divisors[idx];
-}
+static unsigned int div2[] = { 1, 1, 2, 1, 1, 4, 1, 6,
+ 1, 1, 1, 16, 1, 24, 1, 1 };
-static struct clk_ops sh7757_cpu_clk_ops = {
- .recalc = cpu_clk_recalc,
+static struct clk_div_mult_table div4_div_mult_table = {
+ .divisors = div2,
+ .nr_divisors = ARRAY_SIZE(div2),
};
-static struct clk_ops *sh7757_clk_ops[] = {
- &sh7757_master_clk_ops,
- &sh7757_module_clk_ops,
- &sh7757_bus_clk_ops,
- &sh7757_cpu_clk_ops,
+static struct clk_div4_table div4_table = {
+ .div_mult_table = &div4_div_mult_table,
};
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
-{
- if (idx < ARRAY_SIZE(sh7757_clk_ops))
- *ops = sh7757_clk_ops[idx];
-}
+enum { DIV4_I, DIV4_SH, DIV4_P, DIV4_NR };
-static void shyway_clk_recalc(struct clk *clk)
-{
- int idx = (__raw_readl(FRQCR) >> 12) & 0x0000000f;
- clk->rate = clk->parent->rate / sfc_divisors[idx];
-}
-
-static struct clk_ops sh7757_shyway_clk_ops = {
- .recalc = shyway_clk_recalc,
-};
+#define DIV4(_bit, _mask, _flags) \
+ SH_CLK_DIV4(&pll_clk, FRQCR, _bit, _mask, _flags)
-static struct clk sh7757_shyway_clk = {
- .flags = CLK_ENABLE_ON_INIT,
- .ops = &sh7757_shyway_clk_ops,
+struct clk div4_clks[DIV4_NR] = {
+ /*
+ * P clock is always enable, because some P clock modules is used
+ * by Host PC.
+ */
+ [DIV4_P] = DIV4(0, 0x2800, CLK_ENABLE_ON_INIT),
+ [DIV4_SH] = DIV4(12, 0x00a0, CLK_ENABLE_ON_INIT),
+ [DIV4_I] = DIV4(20, 0x0004, CLK_ENABLE_ON_INIT),
};
-/*
- * Additional sh7757-specific on-chip clocks that aren't already part of the
- * clock framework
- */
-static struct clk *sh7757_onchip_clocks[] = {
- &sh7757_shyway_clk,
+#define MSTPCR0 0xffc80030
+#define MSTPCR1 0xffc80034
+
+enum { MSTP004, MSTP000, MSTP114, MSTP113, MSTP112,
+ MSTP111, MSTP110, MSTP103, MSTP102,
+ MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+ /* MSTPCR0 */
+ [MSTP004] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 4, 0),
+ [MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
+
+ /* MSTPCR1 */
+ [MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
+ [MSTP113] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 13, 0),
+ [MSTP112] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 12, 0),
+ [MSTP111] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 11, 0),
+ [MSTP110] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 10, 0),
+ [MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 3, 0),
+ [MSTP102] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 2, 0),
};
#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
static struct clk_lookup lookups[] = {
/* main clocks */
- CLKDEV_CON_ID("shyway_clk", &sh7757_shyway_clk),
+ CLKDEV_CON_ID("extal", &extal_clk),
+ CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+ /* DIV4 clocks */
+ CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+ CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
+ CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+
+ /* MSTP32 clocks */
+ CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP004]),
+ CLKDEV_CON_ID("riic", &mstp_clks[MSTP000]),
+ {
+ /* TMU0 */
+ .dev_id = "sh_tmu.0",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP113],
+ }, {
+ /* TMU1 */
+ .dev_id = "sh_tmu.1",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP114],
+ },
+ {
+ /* SCIF4 (But, ID is 2) */
+ .dev_id = "sh-sci.2",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP112],
+ }, {
+ /* SCIF3 */
+ .dev_id = "sh-sci.1",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP111],
+ }, {
+ /* SCIF2 */
+ .dev_id = "sh-sci.0",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP110],
+ },
+ CLKDEV_CON_ID("usb0", &mstp_clks[MSTP102]),
};
-static int __init sh7757_clk_init(void)
+int __init arch_clk_init(void)
{
- struct clk *clk = clk_get(NULL, "master_clk");
- int i;
-
- for (i = 0; i < ARRAY_SIZE(sh7757_onchip_clocks); i++) {
- struct clk *clkp = sh7757_onchip_clocks[i];
+ int i, ret = 0;
- clkp->parent = clk;
- clk_register(clkp);
- clk_enable(clkp);
- }
+ for (i = 0; i < ARRAY_SIZE(clks); i++)
+ ret |= clk_register(clks[i]);
+ for (i = 0; i < ARRAY_SIZE(lookups); i++)
+ clkdev_add(&lookups[i]);
- /*
- * Now that we have the rest of the clocks registered, we need to
- * force the parent clock to propagate so that these clocks will
- * automatically figure out their rate. We cheat by handing the
- * parent clock its current rate and forcing child propagation.
- */
- clk_set_rate(clk, clk_get_rate(clk));
+ if (!ret)
+ ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+ &div4_table);
+ if (!ret)
+ ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
- clk_put(clk);
-
- clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
- return 0;
+ return ret;
}
-arch_initcall(sh7757_clk_init);
-
diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
index 236a6282d778..4f70df6b6169 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
@@ -5,7 +5,7 @@
*
* Copyright (C) 2006-2007 Renesas Technology Corp.
* Copyright (C) 2006-2007 Renesas Solutions Corp.
- * Copyright (C) 2006-2007 Paul Mundt
+ * Copyright (C) 2006-2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -18,120 +18,179 @@
#include <asm/clock.h>
#include <asm/freq.h>
-static int ifc_divisors[] = { 1, 2, 4 ,6 };
-static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18, 24, 32, 36, 48 };
-static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18, 24, 32, 36, 48 };
-static int cfc_divisors[] = { 1, 1, 4, 6 };
-
-#define IFC_POS 28
-#define IFC_MSK 0x0003
-#define BFC_MSK 0x000f
-#define PFC_MSK 0x000f
-#define CFC_MSK 0x0003
-#define BFC_POS 16
-#define PFC_POS 0
-#define CFC_POS 20
-
-static void master_clk_init(struct clk *clk)
-{
- clk->rate *= pfc_divisors[(__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK];
-}
-
-static struct clk_ops shx3_master_clk_ops = {
- .init = master_clk_init,
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+ .rate = 16666666,
};
-static unsigned long module_clk_recalc(struct clk *clk)
+static unsigned long pll_recalc(struct clk *clk)
{
- int idx = ((__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK);
- return clk->parent->rate / pfc_divisors[idx];
+ /* PLL1 has a fixed x72 multiplier. */
+ return clk->parent->rate * 72;
}
-static struct clk_ops shx3_module_clk_ops = {
- .recalc = module_clk_recalc,
+static struct clk_ops pll_clk_ops = {
+ .recalc = pll_recalc,
};
-static unsigned long bus_clk_recalc(struct clk *clk)
-{
- int idx = ((__raw_readl(FRQCR) >> BFC_POS) & BFC_MSK);
- return clk->parent->rate / bfc_divisors[idx];
-}
+static struct clk pll_clk = {
+ .ops = &pll_clk_ops,
+ .parent = &extal_clk,
+ .flags = CLK_ENABLE_ON_INIT,
+};
-static struct clk_ops shx3_bus_clk_ops = {
- .recalc = bus_clk_recalc,
+static struct clk *clks[] = {
+ &extal_clk,
+ &pll_clk,
};
-static unsigned long cpu_clk_recalc(struct clk *clk)
-{
- int idx = ((__raw_readl(FRQCR) >> IFC_POS) & IFC_MSK);
- return clk->parent->rate / ifc_divisors[idx];
-}
+static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18,
+ 24, 32, 36, 48 };
-static struct clk_ops shx3_cpu_clk_ops = {
- .recalc = cpu_clk_recalc,
+static struct clk_div_mult_table div4_div_mult_table = {
+ .divisors = div2,
+ .nr_divisors = ARRAY_SIZE(div2),
};
-static struct clk_ops *shx3_clk_ops[] = {
- &shx3_master_clk_ops,
- &shx3_module_clk_ops,
- &shx3_bus_clk_ops,
- &shx3_cpu_clk_ops,
+static struct clk_div4_table div4_table = {
+ .div_mult_table = &div4_div_mult_table,
};
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
-{
- if (idx < ARRAY_SIZE(shx3_clk_ops))
- *ops = shx3_clk_ops[idx];
-}
+enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_SHA, DIV4_P, DIV4_NR };
-static unsigned long shyway_clk_recalc(struct clk *clk)
-{
- int idx = ((__raw_readl(FRQCR) >> CFC_POS) & CFC_MSK);
- return clk->parent->rate / cfc_divisors[idx];
-}
+#define DIV4(_bit, _mask, _flags) \
+ SH_CLK_DIV4(&pll_clk, FRQMR1, _bit, _mask, _flags)
-static struct clk_ops shx3_shyway_clk_ops = {
- .recalc = shyway_clk_recalc,
+struct clk div4_clks[DIV4_NR] = {
+ [DIV4_P] = DIV4(0, 0x0f80, 0),
+ [DIV4_SHA] = DIV4(4, 0x0ff0, 0),
+ [DIV4_DDR] = DIV4(12, 0x000c, CLK_ENABLE_ON_INIT),
+ [DIV4_B] = DIV4(16, 0x0fe0, CLK_ENABLE_ON_INIT),
+ [DIV4_SH] = DIV4(20, 0x000c, CLK_ENABLE_ON_INIT),
+ [DIV4_I] = DIV4(28, 0x000e, CLK_ENABLE_ON_INIT),
};
-static struct clk shx3_shyway_clk = {
- .flags = CLK_ENABLE_ON_INIT,
- .ops = &shx3_shyway_clk_ops,
-};
-
-/*
- * Additional SHx3-specific on-chip clocks that aren't already part of the
- * clock framework
- */
-static struct clk *shx3_onchip_clocks[] = {
- &shx3_shyway_clk,
+#define MSTPCR0 0xffc00030
+#define MSTPCR1 0xffc00034
+
+enum { MSTP027, MSTP026, MSTP025, MSTP024,
+ MSTP009, MSTP008, MSTP003, MSTP002,
+ MSTP001, MSTP000, MSTP119, MSTP105,
+ MSTP104, MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+ /* MSTPCR0 */
+ [MSTP027] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 27, 0),
+ [MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
+ [MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
+ [MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
+ [MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
+ [MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
+ [MSTP003] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 3, 0),
+ [MSTP002] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
+ [MSTP001] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 1, 0),
+ [MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
+
+ /* MSTPCR1 */
+ [MSTP119] = SH_CLK_MSTP32(NULL, MSTPCR1, 19, 0),
+ [MSTP105] = SH_CLK_MSTP32(NULL, MSTPCR1, 5, 0),
+ [MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0),
};
#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
static struct clk_lookup lookups[] = {
/* main clocks */
- CLKDEV_CON_ID("shyway_clk", &shx3_shyway_clk),
+ CLKDEV_CON_ID("extal", &extal_clk),
+ CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+ /* DIV4 clocks */
+ CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+ CLKDEV_CON_ID("shywaya_clk", &div4_clks[DIV4_SHA]),
+ CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_DDR]),
+ CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
+ CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
+ CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+
+ /* MSTP32 clocks */
+ {
+ /* SCIF3 */
+ .dev_id = "sh-sci.3",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP027],
+ }, {
+ /* SCIF2 */
+ .dev_id = "sh-sci.2",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP026],
+ }, {
+ /* SCIF1 */
+ .dev_id = "sh-sci.1",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP025],
+ }, {
+ /* SCIF0 */
+ .dev_id = "sh-sci.0",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP024],
+ },
+ CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]),
+ CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]),
+ CLKDEV_CON_ID("fe1_fck", &mstp_clks[MSTP001]),
+ CLKDEV_CON_ID("fe0_fck", &mstp_clks[MSTP000]),
+ {
+ /* TMU0 */
+ .dev_id = "sh_tmu.0",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP008],
+ }, {
+ /* TMU1 */
+ .dev_id = "sh_tmu.1",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP008],
+ }, {
+ /* TMU2 */
+ .dev_id = "sh_tmu.2",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP008],
+ }, {
+ /* TMU3 */
+ .dev_id = "sh_tmu.3",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP009],
+ }, {
+ /* TMU4 */
+ .dev_id = "sh_tmu.4",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP009],
+ }, {
+ /* TMU5 */
+ .dev_id = "sh_tmu.5",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP009],
+ },
+ CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
+ CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
+ CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
};
int __init arch_clk_init(void)
{
- struct clk *clk;
int i, ret = 0;
- cpg_clk_init();
-
- clk = clk_get(NULL, "master_clk");
- for (i = 0; i < ARRAY_SIZE(shx3_onchip_clocks); i++) {
- struct clk *clkp = shx3_onchip_clocks[i];
-
- clkp->parent = clk;
- ret |= clk_register(clkp);
- }
-
- clk_put(clk);
+ for (i = 0; i < ARRAY_SIZE(clks); i++)
+ ret |= clk_register(clks[i]);
+ for (i = 0; i < ARRAY_SIZE(lookups); i++)
+ clkdev_add(&lookups[i]);
- clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+ if (!ret)
+ ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+ &div4_table);
+ if (!ret)
+ ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
return ret;
}
diff --git a/arch/sh/kernel/cpu/sh4a/intc-shx3.c b/arch/sh/kernel/cpu/sh4a/intc-shx3.c
new file mode 100644
index 000000000000..78c971486b4e
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/intc-shx3.c
@@ -0,0 +1,34 @@
+/*
+ * Shared support for SH-X3 interrupt controllers.
+ *
+ * Copyright (C) 2009 - 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/init.h>
+
+#define INTACK 0xfe4100b8
+#define INTACKCLR 0xfe4100bc
+#define INTC_USERIMASK 0xfe411000
+
+#ifdef CONFIG_INTC_BALANCING
+unsigned int irq_lookup(unsigned int irq)
+{
+ return __raw_readl(INTACK) & 1 ? irq : NO_IRQ_IGNORE;
+}
+
+void irq_finish(unsigned int irq)
+{
+ __raw_writel(irq2evt(irq), INTACKCLR);
+}
+#endif
+
+static int __init shx3_irq_setup(void)
+{
+ return register_intc_userimask(INTC_USERIMASK);
+}
+arch_initcall(shx3_irq_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/perf_event.c b/arch/sh/kernel/cpu/sh4a/perf_event.c
index eddc21973fa1..b8b873d8d6b5 100644
--- a/arch/sh/kernel/cpu/sh4a/perf_event.c
+++ b/arch/sh/kernel/cpu/sh4a/perf_event.c
@@ -1,7 +1,7 @@
/*
* Performance events support for SH-4A performance counters
*
- * Copyright (C) 2009 Paul Mundt
+ * Copyright (C) 2009, 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -22,7 +22,25 @@
#define CCBR_CMDS (1 << 1)
#define CCBR_PPCE (1 << 0)
+#ifdef CONFIG_CPU_SHX3
+/*
+ * The PMCAT location for SH-X3 CPUs was quietly moved, while the CCBR
+ * and PMCTR locations remains tentatively constant. This change remains
+ * wholly undocumented, and was simply found through trial and error.
+ *
+ * Early cuts of SH-X3 still appear to use the SH-X/SH-X2 locations, and
+ * it's unclear when this ceased to be the case. For now we always use
+ * the new location (if future parts keep up with this trend then
+ * scanning for them at runtime also remains a viable option.)
+ *
+ * The gap in the register space also suggests that there are other
+ * undocumented counters, so this will need to be revisited at a later
+ * point in time.
+ */
+#define PPC_PMCAT 0xfc100240
+#else
#define PPC_PMCAT 0xfc100080
+#endif
#define PMCAT_OVF3 (1 << 27)
#define PMCAT_CNN3 (1 << 26)
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
index ed23b155c097..4c74bd04bba4 100644
--- a/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
@@ -1,11 +1,11 @@
/*
- * SH7757 (A0 step) Pinmux
+ * SH7757 (B0 step) Pinmux
*
- * Copyright (C) 2009 Renesas Solutions Corp.
+ * Copyright (C) 2009-2010 Renesas Solutions Corp.
*
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
*
- * Based on SH7757 Pinmux
+ * Based on SH7723 Pinmux
* Copyright (C) 2008 Magnus Damm
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -40,27 +40,27 @@ enum {
PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
PTI7_DATA, PTI6_DATA, PTI5_DATA, PTI4_DATA,
PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA,
- PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+ PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL6_DATA, PTL5_DATA, PTL4_DATA,
PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
- PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
- PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ PTN6_DATA, PTN5_DATA, PTN4_DATA,
PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
PTO7_DATA, PTO6_DATA, PTO5_DATA, PTO4_DATA,
PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA,
- PTP6_DATA, PTP5_DATA, PTP4_DATA,
+ PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA,
- PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+ PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
- PTT5_DATA, PTT4_DATA,
+ PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
@@ -95,27 +95,27 @@ enum {
PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
PTI7_IN, PTI6_IN, PTI5_IN, PTI4_IN,
PTI3_IN, PTI2_IN, PTI1_IN, PTI0_IN,
- PTJ7_IN, PTJ6_IN, PTJ5_IN, PTJ4_IN,
+ PTJ6_IN, PTJ5_IN, PTJ4_IN,
PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
- PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
+ PTL6_IN, PTL5_IN, PTL4_IN,
PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
- PTM6_IN, PTM5_IN, PTM4_IN,
+ PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
- PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
+ PTN6_IN, PTN5_IN, PTN4_IN,
PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
PTO7_IN, PTO6_IN, PTO5_IN, PTO4_IN,
PTO3_IN, PTO2_IN, PTO1_IN, PTO0_IN,
- PTP6_IN, PTP5_IN, PTP4_IN,
+ PTP7_IN, PTP6_IN, PTP5_IN, PTP4_IN,
PTP3_IN, PTP2_IN, PTP1_IN, PTP0_IN,
- PTQ6_IN, PTQ5_IN, PTQ4_IN,
+ PTQ6_IN, PTQ5_IN, PTQ4_IN,
PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
PTS7_IN, PTS6_IN, PTS5_IN, PTS4_IN,
PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
- PTT5_IN, PTT4_IN,
+ PTT7_IN, PTT6_IN, PTT5_IN, PTT4_IN,
PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
PTU7_IN, PTU6_IN, PTU5_IN, PTU4_IN,
PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
@@ -132,16 +132,43 @@ enum {
PINMUX_INPUT_END,
PINMUX_INPUT_PULLUP_BEGIN,
+ PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
+ PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
+ PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
+ PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
+ PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
+ PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
+ PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
+ PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
+ PTG7_IN_PU, PTG6_IN_PU, PTG4_IN_PU,
+ PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
+ PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
+ PTI7_IN_PU, PTI6_IN_PU, PTI4_IN_PU,
+ PTI3_IN_PU, PTI2_IN_PU, PTI1_IN_PU, PTI0_IN_PU,
+ PTJ6_IN_PU, PTJ5_IN_PU, PTJ4_IN_PU,
+ PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
+ PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
+ PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
+ PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
+ PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
+ PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
+ PTN4_IN_PU,
+ PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
+ PTO7_IN_PU, PTO6_IN_PU, PTO5_IN_PU, PTO4_IN_PU,
+ PTO3_IN_PU, PTO2_IN_PU, PTO1_IN_PU, PTO0_IN_PU,
+ PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
+ PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
- PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
- PTW7_IN_PU, PTW6_IN_PU, PTW5_IN_PU, PTW4_IN_PU,
- PTW3_IN_PU, PTW2_IN_PU, PTW1_IN_PU, PTW0_IN_PU,
+ PTV3_IN_PU, PTV2_IN_PU,
+ PTW1_IN_PU, PTW0_IN_PU,
PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
+ PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
+ PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
PINMUX_INPUT_PULLUP_END,
PINMUX_OUTPUT_BEGIN,
@@ -163,27 +190,27 @@ enum {
PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
PTI7_OUT, PTI6_OUT, PTI5_OUT, PTI4_OUT,
PTI3_OUT, PTI2_OUT, PTI1_OUT, PTI0_OUT,
- PTJ7_OUT, PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
+ PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
- PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
+ PTL6_OUT, PTL5_OUT, PTL4_OUT,
PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
- PTM6_OUT, PTM5_OUT, PTM4_OUT,
+ PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
- PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
+ PTN6_OUT, PTN5_OUT, PTN4_OUT,
PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
PTO7_OUT, PTO6_OUT, PTO5_OUT, PTO4_OUT,
PTO3_OUT, PTO2_OUT, PTO1_OUT, PTO0_OUT,
- PTP6_OUT, PTP5_OUT, PTP4_OUT,
+ PTP7_OUT, PTP6_OUT, PTP5_OUT, PTP4_OUT,
PTP3_OUT, PTP2_OUT, PTP1_OUT, PTP0_OUT,
- PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
+ PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
PTR3_OUT, PTR2_OUT, PTR1_OUT, PTR0_OUT,
PTS7_OUT, PTS6_OUT, PTS5_OUT, PTS4_OUT,
PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
- PTT5_OUT, PTT4_OUT,
+ PTT7_OUT, PTT6_OUT, PTT5_OUT, PTT4_OUT,
PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
PTU7_OUT, PTU6_OUT, PTU5_OUT, PTU4_OUT,
PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
@@ -218,27 +245,27 @@ enum {
PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
PTI7_FN, PTI6_FN, PTI5_FN, PTI4_FN,
PTI3_FN, PTI2_FN, PTI1_FN, PTI0_FN,
- PTJ7_FN, PTJ6_FN, PTJ5_FN, PTJ4_FN,
+ PTJ6_FN, PTJ5_FN, PTJ4_FN,
PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
- PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN,
+ PTL6_FN, PTL5_FN, PTL4_FN,
PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
- PTM6_FN, PTM5_FN, PTM4_FN,
+ PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
- PTN7_FN, PTN6_FN, PTN5_FN, PTN4_FN,
+ PTN6_FN, PTN5_FN, PTN4_FN,
PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
PTO7_FN, PTO6_FN, PTO5_FN, PTO4_FN,
PTO3_FN, PTO2_FN, PTO1_FN, PTO0_FN,
- PTP6_FN, PTP5_FN, PTP4_FN,
+ PTP7_FN, PTP6_FN, PTP5_FN, PTP4_FN,
PTP3_FN, PTP2_FN, PTP1_FN, PTP0_FN,
- PTQ6_FN, PTQ5_FN, PTQ4_FN,
+ PTQ6_FN, PTQ5_FN, PTQ4_FN,
PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
PTS7_FN, PTS6_FN, PTS5_FN, PTS4_FN,
PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
- PTT5_FN, PTT4_FN,
+ PTT7_FN, PTT6_FN, PTT5_FN, PTT4_FN,
PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
PTU7_FN, PTU6_FN, PTU5_FN, PTU4_FN,
PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
@@ -253,181 +280,248 @@ enum {
PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
- PS0_15_FN1, PS0_15_FN3,
- PS0_14_FN1, PS0_14_FN3,
- PS0_13_FN1, PS0_13_FN3,
- PS0_12_FN1, PS0_12_FN3,
+ PS0_15_FN1, PS0_15_FN2,
+ PS0_14_FN1, PS0_14_FN2,
+ PS0_13_FN1, PS0_13_FN2,
+ PS0_12_FN1, PS0_12_FN2,
+ PS0_11_FN1, PS0_11_FN2,
+ PS0_10_FN1, PS0_10_FN2,
+ PS0_9_FN1, PS0_9_FN2,
+ PS0_8_FN1, PS0_8_FN2,
PS0_7_FN1, PS0_7_FN2,
PS0_6_FN1, PS0_6_FN2,
PS0_5_FN1, PS0_5_FN2,
PS0_4_FN1, PS0_4_FN2,
PS0_3_FN1, PS0_3_FN2,
PS0_2_FN1, PS0_2_FN2,
- PS0_1_FN1, PS0_1_FN2,
- PS1_7_FN1, PS1_7_FN3,
- PS1_6_FN1, PS1_6_FN3,
+ PS1_10_FN1, PS1_10_FN2,
+ PS1_9_FN1, PS1_9_FN2,
+ PS1_8_FN1, PS1_8_FN2,
+ PS1_2_FN1, PS1_2_FN2,
+
+ PS2_13_FN1, PS2_13_FN2,
+ PS2_12_FN1, PS2_12_FN2,
+ PS2_7_FN1, PS2_7_FN2,
+ PS2_6_FN1, PS2_6_FN2,
+ PS2_5_FN1, PS2_5_FN2,
+ PS2_4_FN1, PS2_4_FN2,
+ PS2_2_FN1, PS2_2_FN2,
+
+ PS3_15_FN1, PS3_15_FN2,
+ PS3_14_FN1, PS3_14_FN2,
+ PS3_13_FN1, PS3_13_FN2,
+ PS3_12_FN1, PS3_12_FN2,
+ PS3_11_FN1, PS3_11_FN2,
+ PS3_10_FN1, PS3_10_FN2,
+ PS3_9_FN1, PS3_9_FN2,
+ PS3_8_FN1, PS3_8_FN2,
+ PS3_7_FN1, PS3_7_FN2,
+ PS3_2_FN1, PS3_2_FN2,
+ PS3_1_FN1, PS3_1_FN2,
- PS2_13_FN1, PS2_13_FN3,
- PS2_12_FN1, PS2_12_FN3,
- PS2_1_FN1, PS2_1_FN2,
- PS2_0_FN1, PS2_0_FN2,
-
- PS4_15_FN1, PS4_15_FN2,
PS4_14_FN1, PS4_14_FN2,
PS4_13_FN1, PS4_13_FN2,
PS4_12_FN1, PS4_12_FN2,
- PS4_11_FN1, PS4_11_FN2,
PS4_10_FN1, PS4_10_FN2,
PS4_9_FN1, PS4_9_FN2,
+ PS4_8_FN1, PS4_8_FN2,
+ PS4_4_FN1, PS4_4_FN2,
PS4_3_FN1, PS4_3_FN2,
PS4_2_FN1, PS4_2_FN2,
PS4_1_FN1, PS4_1_FN2,
PS4_0_FN1, PS4_0_FN2,
+ PS5_11_FN1, PS5_11_FN2,
+ PS5_10_FN1, PS5_10_FN2,
PS5_9_FN1, PS5_9_FN2,
PS5_8_FN1, PS5_8_FN2,
PS5_7_FN1, PS5_7_FN2,
PS5_6_FN1, PS5_6_FN2,
PS5_5_FN1, PS5_5_FN2,
PS5_4_FN1, PS5_4_FN2,
-
- /* AN15 to 8 : EVENT15 to 8 */
- PS6_7_FN_AN, PS6_7_FN_EV,
- PS6_6_FN_AN, PS6_6_FN_EV,
- PS6_5_FN_AN, PS6_5_FN_EV,
- PS6_4_FN_AN, PS6_4_FN_EV,
- PS6_3_FN_AN, PS6_3_FN_EV,
- PS6_2_FN_AN, PS6_2_FN_EV,
- PS6_1_FN_AN, PS6_1_FN_EV,
- PS6_0_FN_AN, PS6_0_FN_EV,
-
+ PS5_3_FN1, PS5_3_FN2,
+ PS5_2_FN1, PS5_2_FN2,
+
+ PS6_15_FN1, PS6_15_FN2,
+ PS6_14_FN1, PS6_14_FN2,
+ PS6_13_FN1, PS6_13_FN2,
+ PS6_12_FN1, PS6_12_FN2,
+ PS6_11_FN1, PS6_11_FN2,
+ PS6_10_FN1, PS6_10_FN2,
+ PS6_9_FN1, PS6_9_FN2,
+ PS6_8_FN1, PS6_8_FN2,
+ PS6_7_FN1, PS6_7_FN2,
+ PS6_6_FN1, PS6_6_FN2,
+ PS6_5_FN1, PS6_5_FN2,
+ PS6_4_FN1, PS6_4_FN2,
+ PS6_3_FN1, PS6_3_FN2,
+ PS6_2_FN1, PS6_2_FN2,
+ PS6_1_FN1, PS6_1_FN2,
+ PS6_0_FN1, PS6_0_FN2,
+
+ PS7_15_FN1, PS7_15_FN2,
+ PS7_14_FN1, PS7_14_FN2,
+ PS7_13_FN1, PS7_13_FN2,
+ PS7_12_FN1, PS7_12_FN2,
+ PS7_11_FN1, PS7_11_FN2,
+ PS7_10_FN1, PS7_10_FN2,
+ PS7_9_FN1, PS7_9_FN2,
+ PS7_8_FN1, PS7_8_FN2,
+ PS7_7_FN1, PS7_7_FN2,
+ PS7_6_FN1, PS7_6_FN2,
+ PS7_5_FN1, PS7_5_FN2,
+ PS7_4_FN1, PS7_4_FN2,
+
+ PS8_15_FN1, PS8_15_FN2,
+ PS8_14_FN1, PS8_14_FN2,
+ PS8_13_FN1, PS8_13_FN2,
+ PS8_12_FN1, PS8_12_FN2,
+ PS8_11_FN1, PS8_11_FN2,
+ PS8_10_FN1, PS8_10_FN2,
+ PS8_9_FN1, PS8_9_FN2,
+ PS8_8_FN1, PS8_8_FN2,
PINMUX_FUNCTION_END,
PINMUX_MARK_BEGIN,
- /* PTA (mobule: LBSC, CPG, LPC) */
+ /* PTA (mobule: LBSC, RGMII) */
BS_MARK, RDWR_MARK, WE1_MARK, RDY_MARK,
- MD10_MARK, MD9_MARK, MD8_MARK,
- LGPIO7_MARK, LGPIO6_MARK, LGPIO5_MARK, LGPIO4_MARK,
- LGPIO3_MARK, LGPIO2_MARK, LGPIO1_MARK, LGPIO0_MARK,
-
- /* PTB (mobule: LBSC, EtherC, SIM, LPC) */
- D15_MARK, D14_MARK, D13_MARK, D12_MARK,
- D11_MARK, D10_MARK, D9_MARK, D8_MARK,
ET0_MDC_MARK, ET0_MDIO_MARK, ET1_MDC_MARK, ET1_MDIO_MARK,
- SIM_D_MARK, SIM_CLK_MARK, SIM_RST_MARK,
- WPSZ1_MARK, WPSZ0_MARK, FWID_MARK, FLSHSZ_MARK,
- LPC_SPIEN_MARK, BASEL_MARK,
- /* PTC (mobule: SD) */
- SD_WP_MARK, SD_CD_MARK, SD_CLK_MARK, SD_CMD_MARK,
- SD_D3_MARK, SD_D2_MARK, SD_D1_MARK, SD_D0_MARK,
+ /* PTB (mobule: INTC, ONFI, TMU) */
+ IRQ15_MARK, IRQ14_MARK, IRQ13_MARK, IRQ12_MARK,
+ IRQ11_MARK, IRQ10_MARK, IRQ9_MARK, IRQ8_MARK,
+ ON_NRE_MARK, ON_NWE_MARK, ON_NWP_MARK, ON_NCE0_MARK,
+ ON_R_B0_MARK, ON_ALE_MARK, ON_CLE_MARK, TCLK_MARK,
- /* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+ /* PTC (mobule: IRQ, PWMU) */
IRQ7_MARK, IRQ6_MARK, IRQ5_MARK, IRQ4_MARK,
IRQ3_MARK, IRQ2_MARK, IRQ1_MARK, IRQ0_MARK,
- MD6_MARK, MD5_MARK, MD3_MARK, MD2_MARK,
- MD1_MARK, MD0_MARK, ADTRG1_MARK, ADTRG0_MARK,
-
- /* PTE (mobule: EtherC) */
- ET0_CRS_DV_MARK, ET0_TXD1_MARK,
- ET0_TXD0_MARK, ET0_TX_EN_MARK,
- ET0_REF_CLK_MARK, ET0_RXD1_MARK,
- ET0_RXD0_MARK, ET0_RX_ER_MARK,
-
- /* PTF (mobule: EtherC) */
- ET1_CRS_DV_MARK, ET1_TXD1_MARK,
- ET1_TXD0_MARK, ET1_TX_EN_MARK,
- ET1_REF_CLK_MARK, ET1_RXD1_MARK,
- ET1_RXD0_MARK, ET1_RX_ER_MARK,
-
- /* PTG (mobule: SYSTEM, PWMX, LPC) */
- STATUS0_MARK, STATUS1_MARK,
- PWX0_MARK, PWX1_MARK, PWX2_MARK, PWX3_MARK,
- SERIRQ_MARK, CLKRUN_MARK, LPCPD_MARK, LDRQ_MARK,
-
- /* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
- TCLK_MARK, RXD4_MARK, TXD4_MARK,
+ PWMU0_MARK, PWMU1_MARK, PWMU2_MARK, PWMU3_MARK,
+ PWMU4_MARK, PWMU5_MARK,
+
+ /* PTD (mobule: SPI0, DMAC) */
+ SP0_MOSI_MARK, SP0_MISO_MARK, SP0_SCK_MARK, SP0_SCK_FB_MARK,
+ SP0_SS0_MARK, SP0_SS1_MARK, SP0_SS2_MARK, SP0_SS3_MARK,
+ DREQ0_MARK, DACK0_MARK, TEND0_MARK,
+
+ /* PTE (mobule: RMII) */
+ RMII0_CRS_DV_MARK, RMII0_TXD1_MARK,
+ RMII0_TXD0_MARK, RMII0_TXEN_MARK,
+ RMII0_REFCLK_MARK, RMII0_RXD1_MARK,
+ RMII0_RXD0_MARK, RMII0_RX_ER_MARK,
+
+ /* PTF (mobule: RMII, SerMux) */
+ RMII1_CRS_DV_MARK, RMII1_TXD1_MARK,
+ RMII1_TXD0_MARK, RMII1_TXEN_MARK,
+ RMII1_REFCLK_MARK, RMII1_RXD1_MARK,
+ RMII1_RXD0_MARK, RMII1_RX_ER_MARK,
+ RAC_RI_MARK,
+
+ /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+ BOOTFMS_MARK, BOOTWP_MARK, A25_MARK, A24_MARK,
+ SERIRQ_MARK, WDTOVF_MARK, LPCPD_MARK, LDRQ_MARK,
+ MMCCLK_MARK, MMCCMD_MARK,
+
+ /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
SP1_MOSI_MARK, SP1_MISO_MARK, SP1_SCK_MARK, SP1_SCK_FB_MARK,
- SP1_SS0_MARK, SP1_SS1_MARK, SP0_SS1_MARK,
+ SP1_SS0_MARK, SP1_SS1_MARK, WP_MARK, FMS0_MARK,
+ TEND1_MARK, DREQ1_MARK, DACK1_MARK, ADTRG1_MARK,
+ ADTRG0_MARK,
- /* PTI (mobule: INTC) */
- IRQ15_MARK, IRQ14_MARK, IRQ13_MARK, IRQ12_MARK,
- IRQ11_MARK, IRQ10_MARK, IRQ9_MARK, IRQ8_MARK,
+ /* PTI (mobule: LBSC, SDHI) */
+ D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+ D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+ SD_WP_MARK, SD_CD_MARK, SD_CLK_MARK, SD_CMD_MARK,
+ SD_D3_MARK, SD_D2_MARK, SD_D1_MARK, SD_D0_MARK,
- /* PTJ (mobule: SCIF234, SERMUX) */
- RXD3_MARK, TXD3_MARK, RXD2_MARK, TXD2_MARK,
- COM1_TXD_MARK, COM1_RXD_MARK, COM1_RTS_MARK, COM1_CTS_MARK,
+ /* PTJ (mobule: SCIF234) */
+ RTS3_MARK, CTS3_MARK, TXD3_MARK, RXD3_MARK,
+ RTS4_MARK, RXD4_MARK, TXD4_MARK,
- /* PTK (mobule: SERMUX) */
+ /* PTK (mobule: SERMUX, LBSC, SCIF) */
COM2_TXD_MARK, COM2_RXD_MARK, COM2_RTS_MARK, COM2_CTS_MARK,
- COM2_DTR_MARK, COM2_DSR_MARK, COM2_DCD_MARK, COM2_RI_MARK,
+ COM2_DTR_MARK, COM2_DSR_MARK, COM2_DCD_MARK, CLKOUT_MARK,
+ SCK2_MARK, SCK4_MARK, SCK3_MARK,
- /* PTL (mobule: SERMUX) */
- RAC_TXD_MARK, RAC_RXD_MARK, RAC_RTS_MARK, RAC_CTS_MARK,
- RAC_DTR_MARK, RAC_DSR_MARK, RAC_DCD_MARK, RAC_RI_MARK,
+ /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
+ RAC_RXD_MARK, RAC_RTS_MARK, RAC_CTS_MARK, RAC_DTR_MARK,
+ RAC_DSR_MARK, RAC_DCD_MARK, RAC_TXD_MARK, RXD2_MARK,
+ CS5_MARK, CS6_MARK, AUDSYNC_MARK, AUDCK_MARK,
+ TXD2_MARK,
- /* PTM (mobule: IIC, LPC) */
+ /* PTM (mobule: LBSC, IIC) */
+ CS4_MARK, RD_MARK, WE0_MARK, CS0_MARK,
SDA6_MARK, SCL6_MARK, SDA7_MARK, SCL7_MARK,
- WP_MARK, FMS0_MARK, FMS1_MARK,
- /* PTN (mobule: SCIF234, EVC) */
- SCK2_MARK, RTS4_MARK, RTS3_MARK, RTS2_MARK,
- CTS4_MARK, CTS3_MARK, CTS2_MARK,
- EVENT7_MARK, EVENT6_MARK, EVENT5_MARK, EVENT4_MARK,
- EVENT3_MARK, EVENT2_MARK, EVENT1_MARK, EVENT0_MARK,
+ /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+ VBUS_EN_MARK, VBUS_OC_MARK, JMCTCK_MARK, JMCTMS_MARK,
+ JMCTDO_MARK, JMCTDI_MARK, JMCTRST_MARK,
+ SGPIO1_CLK_MARK, SGPIO1_LOAD_MARK, SGPIO1_DI_MARK,
+ SGPIO1_DO_MARK, SUB_CLKIN_MARK,
- /* PTO (mobule: SGPIO) */
- SGPIO0_CLK_MARK, SGPIO0_LOAD_MARK,
- SGPIO0_DI_MARK, SGPIO0_DO_MARK,
- SGPIO1_CLK_MARK, SGPIO1_LOAD_MARK,
- SGPIO1_DI_MARK, SGPIO1_DO_MARK,
-
- /* PTP (mobule: JMC, SCIF234) */
- JMCTCK_MARK, JMCTMS_MARK, JMCTDO_MARK, JMCTDI_MARK,
- JMCRST_MARK, SCK4_MARK, SCK3_MARK,
+ /* PTO (mobule: SGPIO, SerMux) */
+ SGPIO0_CLK_MARK, SGPIO0_LOAD_MARK, SGPIO0_DI_MARK,
+ SGPIO0_DO_MARK, SGPIO2_CLK_MARK, SGPIO2_LOAD_MARK,
+ SGPIO2_DI_MARK, SGPIO2_DO_MARK,
+ COM1_TXD_MARK, COM1_RXD_MARK, COM1_RTS_MARK, COM1_CTS_MARK,
/* PTQ (mobule: LPC) */
LAD3_MARK, LAD2_MARK, LAD1_MARK, LAD0_MARK,
LFRAME_MARK, LRESET_MARK, LCLK_MARK,
/* PTR (mobule: GRA, IIC) */
- DDC3_MARK, DDC2_MARK,
- SDA8_MARK, SCL8_MARK, SDA2_MARK, SCL2_MARK,
+ DDC3_MARK, DDC2_MARK, SDA2_MARK, SCL2_MARK,
SDA1_MARK, SCL1_MARK, SDA0_MARK, SCL0_MARK,
+ SDA8_MARK, SCL8_MARK,
/* PTS (mobule: GRA, IIC) */
- DDC1_MARK, DDC0_MARK,
- SDA9_MARK, SCL9_MARK, SDA5_MARK, SCL5_MARK,
+ DDC1_MARK, DDC0_MARK, SDA5_MARK, SCL5_MARK,
SDA4_MARK, SCL4_MARK, SDA3_MARK, SCL3_MARK,
+ SDA9_MARK, SCL9_MARK,
- /* PTT (mobule: SYSTEM, PWMX) */
- AUDSYNC_MARK, AUDCK_MARK,
- AUDATA3_MARK, AUDATA2_MARK,
- AUDATA1_MARK, AUDATA0_MARK,
- PWX7_MARK, PWX6_MARK, PWX5_MARK, PWX4_MARK,
+ /* PTT (mobule: PWMX, AUD) */
+ PWMX7_MARK, PWMX6_MARK, PWMX5_MARK, PWMX4_MARK,
+ PWMX3_MARK, PWMX2_MARK, PWMX1_MARK, PWMX0_MARK,
+ AUDATA3_MARK, AUDATA2_MARK, AUDATA1_MARK, AUDATA0_MARK,
+ STATUS1_MARK, STATUS0_MARK,
- /* PTU (mobule: LBSC, DMAC) */
- CS6_MARK, CS5_MARK, CS4_MARK, CS0_MARK,
- RD_MARK, WE0_MARK, A25_MARK, A24_MARK,
- DREQ0_MARK, DACK0_MARK,
+ /* PTU (mobule: LPC, APM) */
+ LGPIO7_MARK, LGPIO6_MARK, LGPIO5_MARK, LGPIO4_MARK,
+ LGPIO3_MARK, LGPIO2_MARK, LGPIO1_MARK, LGPIO0_MARK,
+ APMONCTL_O_MARK, APMPWBTOUT_O_MARK, APMSCI_O_MARK,
+ APMVDDON_MARK, APMSLPBTN_MARK, APMPWRBTN_MARK, APMS5N_MARK,
+ APMS3N_MARK,
- /* PTV (mobule: LBSC, DMAC) */
+ /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
A23_MARK, A22_MARK, A21_MARK, A20_MARK,
A19_MARK, A18_MARK, A17_MARK, A16_MARK,
- TEND0_MARK, DREQ1_MARK, DACK1_MARK, TEND1_MARK,
+ COM2_RI_MARK, R_SPI_MOSI_MARK, R_SPI_MISO_MARK,
+ R_SPI_RSPCK_MARK, R_SPI_SSL0_MARK, R_SPI_SSL1_MARK,
+ EVENT7_MARK, EVENT6_MARK, VBIOS_DI_MARK, VBIOS_DO_MARK,
+ VBIOS_CLK_MARK, VBIOS_CS_MARK,
- /* PTW (mobule: LBSC) */
+ /* PTW (mobule: LBSC, EVC, SCIF) */
A15_MARK, A14_MARK, A13_MARK, A12_MARK,
A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+ EVENT5_MARK, EVENT4_MARK, EVENT3_MARK, EVENT2_MARK,
+ EVENT1_MARK, EVENT0_MARK, CTS4_MARK, CTS2_MARK,
- /* PTX (mobule: LBSC) */
+ /* PTX (mobule: LBSC, SCIF, SIM) */
A7_MARK, A6_MARK, A5_MARK, A4_MARK,
A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+ RTS2_MARK, SIM_D_MARK, SIM_CLK_MARK, SIM_RST_MARK,
/* PTY (mobule: LBSC) */
D7_MARK, D6_MARK, D5_MARK, D4_MARK,
D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+
+ /* PTZ (mobule: eMMC, ONFI) */
+ MMCDAT7_MARK, MMCDAT6_MARK, MMCDAT5_MARK, MMCDAT4_MARK,
+ MMCDAT3_MARK, MMCDAT2_MARK, MMCDAT1_MARK, MMCDAT0_MARK,
+ ON_DQ7_MARK, ON_DQ6_MARK, ON_DQ5_MARK, ON_DQ4_MARK,
+ ON_DQ3_MARK, ON_DQ2_MARK, ON_DQ1_MARK, ON_DQ0_MARK,
+
PINMUX_MARK_END,
};
@@ -473,6 +567,8 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT),
/* PTE GPIO */
+ PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT),
+ PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT),
PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT),
PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT),
PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT),
@@ -521,7 +617,6 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTI0_DATA, PTI0_IN, PTI0_OUT),
/* PTJ GPIO */
- PINMUX_DATA(PTJ7_DATA, PTJ7_IN, PTJ7_OUT),
PINMUX_DATA(PTJ6_DATA, PTJ6_IN, PTJ6_OUT),
PINMUX_DATA(PTJ5_DATA, PTJ5_IN, PTJ5_OUT),
PINMUX_DATA(PTJ4_DATA, PTJ4_IN, PTJ4_OUT),
@@ -541,7 +636,6 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT),
/* PTL GPIO */
- PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT),
PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT),
PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT),
PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT),
@@ -560,7 +654,6 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT),
/* PTN GPIO */
- PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT),
PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT),
PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT),
PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT),
@@ -609,6 +702,8 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT),
/* PTT GPIO */
+ PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT),
+ PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT),
PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT),
PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT),
PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT),
@@ -677,186 +772,204 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT),
/* PTA FN */
- PINMUX_DATA(BS_MARK, PS0_15_FN1, PTA7_FN),
- PINMUX_DATA(LGPIO7_MARK, PS0_15_FN3, PTA7_FN),
- PINMUX_DATA(RDWR_MARK, PS0_14_FN1, PTA6_FN),
- PINMUX_DATA(LGPIO6_MARK, PS0_14_FN3, PTA6_FN),
- PINMUX_DATA(WE1_MARK, PS0_13_FN1, PTA5_FN),
- PINMUX_DATA(LGPIO5_MARK, PS0_13_FN3, PTA5_FN),
- PINMUX_DATA(RDY_MARK, PS0_12_FN1, PTA4_FN),
- PINMUX_DATA(LGPIO4_MARK, PS0_12_FN3, PTA4_FN),
- PINMUX_DATA(LGPIO3_MARK, PTA3_FN),
- PINMUX_DATA(LGPIO2_MARK, PTA2_FN),
- PINMUX_DATA(LGPIO1_MARK, PTA1_FN),
- PINMUX_DATA(LGPIO0_MARK, PTA0_FN),
+ PINMUX_DATA(BS_MARK, PTA7_FN),
+ PINMUX_DATA(RDWR_MARK, PTA6_FN),
+ PINMUX_DATA(WE1_MARK, PTA5_FN),
+ PINMUX_DATA(RDY_MARK, PTA4_FN),
+ PINMUX_DATA(ET0_MDC_MARK, PTA3_FN),
+ PINMUX_DATA(ET0_MDIO_MARK, PTA2_FN),
+ PINMUX_DATA(ET1_MDC_MARK, PTA1_FN),
+ PINMUX_DATA(ET1_MDIO_MARK, PTA0_FN),
/* PTB FN */
- PINMUX_DATA(D15_MARK, PS0_7_FN1, PTB7_FN),
- PINMUX_DATA(ET0_MDC_MARK, PS0_7_FN2, PTB7_FN),
- PINMUX_DATA(D14_MARK, PS0_6_FN1, PTB6_FN),
- PINMUX_DATA(ET0_MDIO_MARK, PS0_6_FN2, PTB6_FN),
- PINMUX_DATA(D13_MARK, PS0_5_FN1, PTB5_FN),
- PINMUX_DATA(ET1_MDC_MARK, PS0_5_FN2, PTB5_FN),
- PINMUX_DATA(D12_MARK, PS0_4_FN1, PTB4_FN),
- PINMUX_DATA(ET1_MDIO_MARK, PS0_4_FN2, PTB4_FN),
- PINMUX_DATA(D11_MARK, PS0_3_FN1, PTB3_FN),
- PINMUX_DATA(SIM_D_MARK, PS0_3_FN2, PTB3_FN),
- PINMUX_DATA(D10_MARK, PS0_2_FN1, PTB2_FN),
- PINMUX_DATA(SIM_CLK_MARK, PS0_2_FN2, PTB2_FN),
- PINMUX_DATA(D9_MARK, PS0_1_FN1, PTB1_FN),
- PINMUX_DATA(SIM_RST_MARK, PS0_1_FN2, PTB1_FN),
- PINMUX_DATA(D8_MARK, PTB0_FN),
+ PINMUX_DATA(IRQ15_MARK, PS0_15_FN1, PTB7_FN),
+ PINMUX_DATA(ON_NRE_MARK, PS0_15_FN2, PTB7_FN),
+ PINMUX_DATA(IRQ14_MARK, PS0_14_FN1, PTB6_FN),
+ PINMUX_DATA(ON_NWE_MARK, PS0_14_FN2, PTB6_FN),
+ PINMUX_DATA(IRQ13_MARK, PS0_13_FN1, PTB5_FN),
+ PINMUX_DATA(ON_NWP_MARK, PS0_13_FN2, PTB5_FN),
+ PINMUX_DATA(IRQ12_MARK, PS0_12_FN1, PTB4_FN),
+ PINMUX_DATA(ON_NCE0_MARK, PS0_12_FN2, PTB4_FN),
+ PINMUX_DATA(IRQ11_MARK, PS0_11_FN1, PTB3_FN),
+ PINMUX_DATA(ON_R_B0_MARK, PS0_11_FN2, PTB3_FN),
+ PINMUX_DATA(IRQ10_MARK, PS0_10_FN1, PTB2_FN),
+ PINMUX_DATA(ON_ALE_MARK, PS0_10_FN2, PTB2_FN),
+ PINMUX_DATA(IRQ9_MARK, PS0_9_FN1, PTB1_FN),
+ PINMUX_DATA(ON_CLE_MARK, PS0_9_FN2, PTB1_FN),
+ PINMUX_DATA(IRQ8_MARK, PS0_8_FN1, PTB0_FN),
+ PINMUX_DATA(TCLK_MARK, PS0_8_FN2, PTB0_FN),
/* PTC FN */
- PINMUX_DATA(SD_WP_MARK, PTC7_FN),
- PINMUX_DATA(SD_CD_MARK, PTC6_FN),
- PINMUX_DATA(SD_CLK_MARK, PTC5_FN),
- PINMUX_DATA(SD_CMD_MARK, PTC4_FN),
- PINMUX_DATA(SD_D3_MARK, PTC3_FN),
- PINMUX_DATA(SD_D2_MARK, PTC2_FN),
- PINMUX_DATA(SD_D1_MARK, PTC1_FN),
- PINMUX_DATA(SD_D0_MARK, PTC0_FN),
+ PINMUX_DATA(IRQ7_MARK, PS0_7_FN1, PTC7_FN),
+ PINMUX_DATA(PWMU0_MARK, PS0_7_FN2, PTC7_FN),
+ PINMUX_DATA(IRQ6_MARK, PS0_6_FN1, PTC6_FN),
+ PINMUX_DATA(PWMU1_MARK, PS0_6_FN2, PTC6_FN),
+ PINMUX_DATA(IRQ5_MARK, PS0_5_FN1, PTC5_FN),
+ PINMUX_DATA(PWMU2_MARK, PS0_5_FN2, PTC5_FN),
+ PINMUX_DATA(IRQ4_MARK, PS0_4_FN1, PTC5_FN),
+ PINMUX_DATA(PWMU3_MARK, PS0_4_FN2, PTC4_FN),
+ PINMUX_DATA(IRQ3_MARK, PS0_3_FN1, PTC3_FN),
+ PINMUX_DATA(PWMU4_MARK, PS0_3_FN2, PTC3_FN),
+ PINMUX_DATA(IRQ2_MARK, PS0_2_FN1, PTC2_FN),
+ PINMUX_DATA(PWMU5_MARK, PS0_2_FN2, PTC2_FN),
+ PINMUX_DATA(IRQ1_MARK, PTC1_FN),
+ PINMUX_DATA(IRQ0_MARK, PTC0_FN),
/* PTD FN */
- PINMUX_DATA(IRQ7_MARK, PS1_7_FN1, PTD7_FN),
- PINMUX_DATA(ADTRG1_MARK, PS1_7_FN3, PTD7_FN),
- PINMUX_DATA(IRQ6_MARK, PS1_6_FN1, PTD6_FN),
- PINMUX_DATA(ADTRG0_MARK, PS1_6_FN3, PTD6_FN),
- PINMUX_DATA(IRQ5_MARK, PTD5_FN),
- PINMUX_DATA(IRQ4_MARK, PTD4_FN),
- PINMUX_DATA(IRQ3_MARK, PTD3_FN),
- PINMUX_DATA(IRQ2_MARK, PTD2_FN),
- PINMUX_DATA(IRQ1_MARK, PTD1_FN),
- PINMUX_DATA(IRQ0_MARK, PTD0_FN),
+ PINMUX_DATA(SP0_MOSI_MARK, PTD7_FN),
+ PINMUX_DATA(SP0_MISO_MARK, PTD6_FN),
+ PINMUX_DATA(SP0_SCK_MARK, PTD5_FN),
+ PINMUX_DATA(SP0_SCK_FB_MARK, PTD4_FN),
+ PINMUX_DATA(SP0_SS0_MARK, PTD3_FN),
+ PINMUX_DATA(SP0_SS1_MARK, PS1_10_FN1, PTD2_FN),
+ PINMUX_DATA(DREQ0_MARK, PS1_10_FN2, PTD2_FN),
+ PINMUX_DATA(SP0_SS2_MARK, PS1_9_FN1, PTD1_FN),
+ PINMUX_DATA(DACK0_MARK, PS1_9_FN2, PTD1_FN),
+ PINMUX_DATA(SP0_SS3_MARK, PS1_8_FN1, PTD0_FN),
+ PINMUX_DATA(TEND0_MARK, PS1_8_FN2, PTD0_FN),
/* PTE FN */
- PINMUX_DATA(ET0_CRS_DV_MARK, PTE7_FN),
- PINMUX_DATA(ET0_TXD1_MARK, PTE6_FN),
- PINMUX_DATA(ET0_TXD0_MARK, PTE5_FN),
- PINMUX_DATA(ET0_TX_EN_MARK, PTE4_FN),
- PINMUX_DATA(ET0_REF_CLK_MARK, PTE3_FN),
- PINMUX_DATA(ET0_RXD1_MARK, PTE2_FN),
- PINMUX_DATA(ET0_RXD0_MARK, PTE1_FN),
- PINMUX_DATA(ET0_RX_ER_MARK, PTE0_FN),
+ PINMUX_DATA(RMII0_CRS_DV_MARK, PTE7_FN),
+ PINMUX_DATA(RMII0_TXD1_MARK, PTE6_FN),
+ PINMUX_DATA(RMII0_TXD0_MARK, PTE5_FN),
+ PINMUX_DATA(RMII0_TXEN_MARK, PTE4_FN),
+ PINMUX_DATA(RMII0_REFCLK_MARK, PTE3_FN),
+ PINMUX_DATA(RMII0_RXD1_MARK, PTE2_FN),
+ PINMUX_DATA(RMII0_RXD0_MARK, PTE1_FN),
+ PINMUX_DATA(RMII0_RX_ER_MARK, PTE0_FN),
/* PTF FN */
- PINMUX_DATA(ET1_CRS_DV_MARK, PTF7_FN),
- PINMUX_DATA(ET1_TXD1_MARK, PTF6_FN),
- PINMUX_DATA(ET1_TXD0_MARK, PTF5_FN),
- PINMUX_DATA(ET1_TX_EN_MARK, PTF4_FN),
- PINMUX_DATA(ET1_REF_CLK_MARK, PTF3_FN),
- PINMUX_DATA(ET1_RXD1_MARK, PTF2_FN),
- PINMUX_DATA(ET1_RXD0_MARK, PTF1_FN),
- PINMUX_DATA(ET1_RX_ER_MARK, PTF0_FN),
+ PINMUX_DATA(RMII1_CRS_DV_MARK, PTF7_FN),
+ PINMUX_DATA(RMII1_TXD1_MARK, PTF6_FN),
+ PINMUX_DATA(RMII1_TXD0_MARK, PTF5_FN),
+ PINMUX_DATA(RMII1_TXEN_MARK, PTF4_FN),
+ PINMUX_DATA(RMII1_REFCLK_MARK, PTF3_FN),
+ PINMUX_DATA(RMII1_RXD1_MARK, PS1_2_FN1, PTF2_FN),
+ PINMUX_DATA(RAC_RI_MARK, PS1_2_FN2, PTF2_FN),
+ PINMUX_DATA(RMII1_RXD0_MARK, PTF1_FN),
+ PINMUX_DATA(RMII1_RX_ER_MARK, PTF0_FN),
/* PTG FN */
- PINMUX_DATA(PWX0_MARK, PTG7_FN),
- PINMUX_DATA(PWX1_MARK, PTG6_FN),
- PINMUX_DATA(STATUS0_MARK, PS2_13_FN1, PTG5_FN),
- PINMUX_DATA(PWX2_MARK, PS2_13_FN3, PTG5_FN),
- PINMUX_DATA(STATUS1_MARK, PS2_12_FN1, PTG4_FN),
- PINMUX_DATA(PWX3_MARK, PS2_12_FN3, PTG4_FN),
+ PINMUX_DATA(BOOTFMS_MARK, PTG7_FN),
+ PINMUX_DATA(BOOTWP_MARK, PTG6_FN),
+ PINMUX_DATA(A25_MARK, PS2_13_FN1, PTG5_FN),
+ PINMUX_DATA(MMCCLK_MARK, PS2_13_FN2, PTG5_FN),
+ PINMUX_DATA(A24_MARK, PS2_12_FN1, PTG4_FN),
+ PINMUX_DATA(MMCCMD_MARK, PS2_12_FN2, PTG4_FN),
PINMUX_DATA(SERIRQ_MARK, PTG3_FN),
- PINMUX_DATA(CLKRUN_MARK, PTG2_FN),
+ PINMUX_DATA(WDTOVF_MARK, PTG2_FN),
PINMUX_DATA(LPCPD_MARK, PTG1_FN),
PINMUX_DATA(LDRQ_MARK, PTG0_FN),
/* PTH FN */
- PINMUX_DATA(SP1_MOSI_MARK, PTH7_FN),
- PINMUX_DATA(SP1_MISO_MARK, PTH6_FN),
- PINMUX_DATA(SP1_SCK_MARK, PTH5_FN),
- PINMUX_DATA(SP1_SCK_FB_MARK, PTH4_FN),
+ PINMUX_DATA(SP1_MOSI_MARK, PS2_7_FN1, PTH7_FN),
+ PINMUX_DATA(TEND1_MARK, PS2_7_FN2, PTH7_FN),
+ PINMUX_DATA(SP1_MISO_MARK, PS2_6_FN1, PTH6_FN),
+ PINMUX_DATA(DREQ1_MARK, PS2_6_FN2, PTH6_FN),
+ PINMUX_DATA(SP1_SCK_MARK, PS2_5_FN1, PTH5_FN),
+ PINMUX_DATA(DACK1_MARK, PS2_5_FN2, PTH5_FN),
+ PINMUX_DATA(SP1_SCK_FB_MARK, PS2_4_FN1, PTH4_FN),
+ PINMUX_DATA(ADTRG1_MARK, PS2_4_FN2, PTH4_FN),
PINMUX_DATA(SP1_SS0_MARK, PTH3_FN),
- PINMUX_DATA(TCLK_MARK, PTH2_FN),
- PINMUX_DATA(RXD4_MARK, PS2_1_FN1, PTH1_FN),
- PINMUX_DATA(SP1_SS1_MARK, PS2_1_FN2, PTH1_FN),
- PINMUX_DATA(TXD4_MARK, PS2_0_FN1, PTH0_FN),
- PINMUX_DATA(SP0_SS1_MARK, PS2_0_FN2, PTH0_FN),
+ PINMUX_DATA(SP1_SS1_MARK, PS2_2_FN1, PTH2_FN),
+ PINMUX_DATA(ADTRG0_MARK, PS2_2_FN2, PTH2_FN),
+ PINMUX_DATA(WP_MARK, PTH1_FN),
+ PINMUX_DATA(FMS0_MARK, PTH0_FN),
/* PTI FN */
- PINMUX_DATA(IRQ15_MARK, PTI7_FN),
- PINMUX_DATA(IRQ14_MARK, PTI6_FN),
- PINMUX_DATA(IRQ13_MARK, PTI5_FN),
- PINMUX_DATA(IRQ12_MARK, PTI4_FN),
- PINMUX_DATA(IRQ11_MARK, PTI3_FN),
- PINMUX_DATA(IRQ10_MARK, PTI2_FN),
- PINMUX_DATA(IRQ9_MARK, PTI1_FN),
- PINMUX_DATA(IRQ8_MARK, PTI0_FN),
+ PINMUX_DATA(D15_MARK, PS3_15_FN1, PTI7_FN),
+ PINMUX_DATA(SD_WP_MARK, PS3_15_FN2, PTI7_FN),
+ PINMUX_DATA(D14_MARK, PS3_14_FN1, PTI6_FN),
+ PINMUX_DATA(SD_CD_MARK, PS3_14_FN2, PTI6_FN),
+ PINMUX_DATA(D13_MARK, PS3_13_FN1, PTI5_FN),
+ PINMUX_DATA(SD_CLK_MARK, PS3_13_FN2, PTI5_FN),
+ PINMUX_DATA(D12_MARK, PS3_12_FN1, PTI4_FN),
+ PINMUX_DATA(SD_CMD_MARK, PS3_12_FN2, PTI4_FN),
+ PINMUX_DATA(D11_MARK, PS3_11_FN1, PTI3_FN),
+ PINMUX_DATA(SD_D3_MARK, PS3_11_FN2, PTI3_FN),
+ PINMUX_DATA(D10_MARK, PS3_10_FN1, PTI2_FN),
+ PINMUX_DATA(SD_D2_MARK, PS3_10_FN2, PTI2_FN),
+ PINMUX_DATA(D9_MARK, PS3_9_FN1, PTI1_FN),
+ PINMUX_DATA(SD_D1_MARK, PS3_9_FN2, PTI1_FN),
+ PINMUX_DATA(D8_MARK, PS3_8_FN1, PTI0_FN),
+ PINMUX_DATA(SD_D0_MARK, PS3_8_FN2, PTI0_FN),
/* PTJ FN */
- PINMUX_DATA(RXD3_MARK, PTJ7_FN),
- PINMUX_DATA(TXD3_MARK, PTJ6_FN),
- PINMUX_DATA(RXD2_MARK, PTJ5_FN),
- PINMUX_DATA(TXD2_MARK, PTJ4_FN),
- PINMUX_DATA(COM1_TXD_MARK, PTJ3_FN),
- PINMUX_DATA(COM1_RXD_MARK, PTJ2_FN),
- PINMUX_DATA(COM1_RTS_MARK, PTJ1_FN),
- PINMUX_DATA(COM1_CTS_MARK, PTJ0_FN),
+ PINMUX_DATA(RTS3_MARK, PTJ6_FN),
+ PINMUX_DATA(CTS3_MARK, PTJ5_FN),
+ PINMUX_DATA(TXD3_MARK, PTJ4_FN),
+ PINMUX_DATA(RXD3_MARK, PTJ3_FN),
+ PINMUX_DATA(RTS4_MARK, PTJ2_FN),
+ PINMUX_DATA(RXD4_MARK, PTJ1_FN),
+ PINMUX_DATA(TXD4_MARK, PTJ0_FN),
/* PTK FN */
- PINMUX_DATA(COM2_TXD_MARK, PTK7_FN),
+ PINMUX_DATA(COM2_TXD_MARK, PS3_7_FN1, PTK7_FN),
+ PINMUX_DATA(SCK2_MARK, PS3_7_FN2, PTK7_FN),
PINMUX_DATA(COM2_RXD_MARK, PTK6_FN),
PINMUX_DATA(COM2_RTS_MARK, PTK5_FN),
PINMUX_DATA(COM2_CTS_MARK, PTK4_FN),
PINMUX_DATA(COM2_DTR_MARK, PTK3_FN),
- PINMUX_DATA(COM2_DSR_MARK, PTK2_FN),
- PINMUX_DATA(COM2_DCD_MARK, PTK1_FN),
- PINMUX_DATA(COM2_RI_MARK, PTK0_FN),
+ PINMUX_DATA(COM2_DSR_MARK, PS3_2_FN1, PTK2_FN),
+ PINMUX_DATA(SCK4_MARK, PS3_2_FN2, PTK2_FN),
+ PINMUX_DATA(COM2_DCD_MARK, PS3_1_FN1, PTK1_FN),
+ PINMUX_DATA(SCK3_MARK, PS3_1_FN2, PTK1_FN),
+ PINMUX_DATA(CLKOUT_MARK, PTK0_FN),
/* PTL FN */
- PINMUX_DATA(RAC_TXD_MARK, PTL7_FN),
- PINMUX_DATA(RAC_RXD_MARK, PTL6_FN),
- PINMUX_DATA(RAC_RTS_MARK, PTL5_FN),
- PINMUX_DATA(RAC_CTS_MARK, PTL4_FN),
+ PINMUX_DATA(RAC_RXD_MARK, PS4_14_FN1, PTL6_FN),
+ PINMUX_DATA(RXD2_MARK, PS4_14_FN2, PTL6_FN),
+ PINMUX_DATA(RAC_RTS_MARK, PS4_13_FN1, PTL5_FN),
+ PINMUX_DATA(CS5_MARK, PS4_13_FN2, PTL5_FN),
+ PINMUX_DATA(RAC_CTS_MARK, PS4_12_FN1, PTL4_FN),
+ PINMUX_DATA(CS6_MARK, PS4_12_FN2, PTL4_FN),
PINMUX_DATA(RAC_DTR_MARK, PTL3_FN),
- PINMUX_DATA(RAC_DSR_MARK, PTL2_FN),
- PINMUX_DATA(RAC_DCD_MARK, PTL1_FN),
- PINMUX_DATA(RAC_RI_MARK, PTL0_FN),
+ PINMUX_DATA(RAC_DSR_MARK, PS4_10_FN1, PTL2_FN),
+ PINMUX_DATA(AUDSYNC_MARK, PS4_10_FN2, PTL2_FN),
+ PINMUX_DATA(RAC_DCD_MARK, PS4_9_FN1, PTL1_FN),
+ PINMUX_DATA(AUDCK_MARK, PS4_9_FN2, PTL1_FN),
+ PINMUX_DATA(RAC_TXD_MARK, PS4_8_FN1, PTL0_FN),
+ PINMUX_DATA(TXD2_MARK, PS4_8_FN1, PTL0_FN),
/* PTM FN */
- PINMUX_DATA(WP_MARK, PTM6_FN),
- PINMUX_DATA(FMS0_MARK, PTM5_FN),
- PINMUX_DATA(FMS1_MARK, PTM4_FN),
+ PINMUX_DATA(CS4_MARK, PTM7_FN),
+ PINMUX_DATA(RD_MARK, PTM6_FN),
+ PINMUX_DATA(WE0_MARK, PTM7_FN),
+ PINMUX_DATA(CS0_MARK, PTM4_FN),
PINMUX_DATA(SDA6_MARK, PTM3_FN),
PINMUX_DATA(SCL6_MARK, PTM2_FN),
PINMUX_DATA(SDA7_MARK, PTM1_FN),
PINMUX_DATA(SCL7_MARK, PTM0_FN),
/* PTN FN */
- PINMUX_DATA(SCK2_MARK, PS4_15_FN1, PTN7_FN),
- PINMUX_DATA(EVENT7_MARK, PS4_15_FN2, PTN7_FN),
- PINMUX_DATA(RTS4_MARK, PS4_14_FN1, PTN6_FN),
- PINMUX_DATA(EVENT6_MARK, PS4_14_FN2, PTN6_FN),
- PINMUX_DATA(RTS3_MARK, PS4_13_FN1, PTN5_FN),
- PINMUX_DATA(EVENT5_MARK, PS4_13_FN2, PTN5_FN),
- PINMUX_DATA(RTS2_MARK, PS4_12_FN1, PTN4_FN),
- PINMUX_DATA(EVENT4_MARK, PS4_12_FN2, PTN4_FN),
- PINMUX_DATA(CTS4_MARK, PS4_11_FN1, PTN3_FN),
- PINMUX_DATA(EVENT3_MARK, PS4_11_FN2, PTN3_FN),
- PINMUX_DATA(CTS3_MARK, PS4_10_FN1, PTN2_FN),
- PINMUX_DATA(EVENT2_MARK, PS4_10_FN2, PTN2_FN),
- PINMUX_DATA(CTS2_MARK, PS4_9_FN1, PTN1_FN),
- PINMUX_DATA(EVENT1_MARK, PS4_9_FN2, PTN1_FN),
- PINMUX_DATA(EVENT0_MARK, PTN0_FN),
+ PINMUX_DATA(VBUS_EN_MARK, PTN6_FN),
+ PINMUX_DATA(VBUS_OC_MARK, PTN5_FN),
+ PINMUX_DATA(JMCTCK_MARK, PS4_4_FN1, PTN4_FN),
+ PINMUX_DATA(SGPIO1_CLK_MARK, PS4_4_FN2, PTN4_FN),
+ PINMUX_DATA(JMCTMS_MARK, PS4_3_FN1, PTN5_FN),
+ PINMUX_DATA(SGPIO1_LOAD_MARK, PS4_3_FN2, PTN5_FN),
+ PINMUX_DATA(JMCTDO_MARK, PS4_2_FN1, PTN2_FN),
+ PINMUX_DATA(SGPIO1_DO_MARK, PS4_2_FN2, PTN2_FN),
+ PINMUX_DATA(JMCTDI_MARK, PS4_1_FN1, PTN1_FN),
+ PINMUX_DATA(SGPIO1_DI_MARK, PS4_1_FN2, PTN1_FN),
+ PINMUX_DATA(JMCTRST_MARK, PS4_0_FN1, PTN0_FN),
+ PINMUX_DATA(SUB_CLKIN_MARK, PS4_0_FN2, PTN0_FN),
/* PTO FN */
PINMUX_DATA(SGPIO0_CLK_MARK, PTO7_FN),
PINMUX_DATA(SGPIO0_LOAD_MARK, PTO6_FN),
PINMUX_DATA(SGPIO0_DI_MARK, PTO5_FN),
PINMUX_DATA(SGPIO0_DO_MARK, PTO4_FN),
- PINMUX_DATA(SGPIO1_CLK_MARK, PTO3_FN),
- PINMUX_DATA(SGPIO1_LOAD_MARK, PTO2_FN),
- PINMUX_DATA(SGPIO1_DI_MARK, PTO1_FN),
- PINMUX_DATA(SGPIO1_DO_MARK, PTO0_FN),
+ PINMUX_DATA(SGPIO2_CLK_MARK, PS5_11_FN1, PTO3_FN),
+ PINMUX_DATA(COM1_TXD_MARK, PS5_11_FN2, PTO3_FN),
+ PINMUX_DATA(SGPIO2_LOAD_MARK, PS5_10_FN1, PTO2_FN),
+ PINMUX_DATA(COM1_RXD_MARK, PS5_10_FN2, PTO2_FN),
+ PINMUX_DATA(SGPIO2_DI_MARK, PS5_9_FN1, PTO1_FN),
+ PINMUX_DATA(COM1_RTS_MARK, PS5_9_FN2, PTO1_FN),
+ PINMUX_DATA(SGPIO2_DO_MARK, PS5_8_FN1, PTO0_FN),
+ PINMUX_DATA(COM1_CTS_MARK, PS5_8_FN2, PTO0_FN),
/* PTP FN */
- PINMUX_DATA(JMCTCK_MARK, PTP6_FN),
- PINMUX_DATA(JMCTMS_MARK, PTP5_FN),
- PINMUX_DATA(JMCTDO_MARK, PTP4_FN),
- PINMUX_DATA(JMCTDI_MARK, PTP3_FN),
- PINMUX_DATA(JMCRST_MARK, PTP2_FN),
- PINMUX_DATA(SCK4_MARK, PTP1_FN),
- PINMUX_DATA(SCK3_MARK, PTP0_FN),
/* PTQ FN */
PINMUX_DATA(LAD3_MARK, PTQ6_FN),
@@ -864,8 +977,8 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(LAD1_MARK, PTQ4_FN),
PINMUX_DATA(LAD0_MARK, PTQ3_FN),
PINMUX_DATA(LFRAME_MARK, PTQ2_FN),
- PINMUX_DATA(SCK4_MARK, PTQ1_FN),
- PINMUX_DATA(SCK3_MARK, PTQ0_FN),
+ PINMUX_DATA(LRESET_MARK, PTQ1_FN),
+ PINMUX_DATA(LCLK_MARK, PTQ0_FN),
/* PTR FN */
PINMUX_DATA(SDA8_MARK, PTR7_FN), /* DDC3? */
@@ -888,58 +1001,84 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(SCL3_MARK, PTS0_FN),
/* PTT FN */
- PINMUX_DATA(AUDSYNC_MARK, PTS5_FN),
- PINMUX_DATA(AUDCK_MARK, PTS4_FN),
- PINMUX_DATA(AUDATA3_MARK, PS4_3_FN1, PTS3_FN),
- PINMUX_DATA(PWX7_MARK, PS4_3_FN2, PTS3_FN),
- PINMUX_DATA(AUDATA2_MARK, PS4_2_FN1, PTS2_FN),
- PINMUX_DATA(PWX6_MARK, PS4_2_FN2, PTS2_FN),
- PINMUX_DATA(AUDATA1_MARK, PS4_1_FN1, PTS1_FN),
- PINMUX_DATA(PWX5_MARK, PS4_1_FN2, PTS1_FN),
- PINMUX_DATA(AUDATA0_MARK, PS4_0_FN1, PTS0_FN),
- PINMUX_DATA(PWX4_MARK, PS4_0_FN2, PTS0_FN),
+ PINMUX_DATA(PWMX7_MARK, PS5_7_FN1, PTT7_FN),
+ PINMUX_DATA(AUDATA3_MARK, PS5_7_FN2, PTT7_FN),
+ PINMUX_DATA(PWMX6_MARK, PS5_6_FN1, PTT6_FN),
+ PINMUX_DATA(AUDATA2_MARK, PS5_6_FN2, PTT6_FN),
+ PINMUX_DATA(PWMX5_MARK, PS5_5_FN1, PTT5_FN),
+ PINMUX_DATA(AUDATA1_MARK, PS5_5_FN2, PTT5_FN),
+ PINMUX_DATA(PWMX4_MARK, PS5_4_FN1, PTT4_FN),
+ PINMUX_DATA(AUDATA0_MARK, PS5_4_FN2, PTT4_FN),
+ PINMUX_DATA(PWMX3_MARK, PS5_3_FN1, PTT3_FN),
+ PINMUX_DATA(STATUS1_MARK, PS5_3_FN2, PTT3_FN),
+ PINMUX_DATA(PWMX2_MARK, PS5_2_FN1, PTT2_FN),
+ PINMUX_DATA(STATUS0_MARK, PS5_2_FN2, PTT2_FN),
+ PINMUX_DATA(PWMX1_MARK, PTT1_FN),
+ PINMUX_DATA(PWMX0_MARK, PTT0_FN),
/* PTU FN */
- PINMUX_DATA(CS6_MARK, PTU7_FN),
- PINMUX_DATA(CS5_MARK, PTU6_FN),
- PINMUX_DATA(CS4_MARK, PTU5_FN),
- PINMUX_DATA(CS0_MARK, PTU4_FN),
- PINMUX_DATA(RD_MARK, PTU3_FN),
- PINMUX_DATA(WE0_MARK, PTU2_FN),
- PINMUX_DATA(A25_MARK, PS5_9_FN1, PTU1_FN),
- PINMUX_DATA(DREQ0_MARK, PS5_9_FN2, PTU1_FN),
- PINMUX_DATA(A24_MARK, PS5_8_FN1, PTU0_FN),
- PINMUX_DATA(DACK0_MARK, PS5_8_FN2, PTU0_FN),
+ PINMUX_DATA(LGPIO7_MARK, PS6_15_FN1, PTU7_FN),
+ PINMUX_DATA(APMONCTL_O_MARK, PS6_15_FN2, PTU7_FN),
+ PINMUX_DATA(LGPIO6_MARK, PS6_14_FN1, PTU6_FN),
+ PINMUX_DATA(APMPWBTOUT_O_MARK, PS6_14_FN2, PTU6_FN),
+ PINMUX_DATA(LGPIO5_MARK, PS6_13_FN1, PTU5_FN),
+ PINMUX_DATA(APMSCI_O_MARK, PS6_13_FN2, PTU5_FN),
+ PINMUX_DATA(LGPIO4_MARK, PS6_12_FN1, PTU4_FN),
+ PINMUX_DATA(APMVDDON_MARK, PS6_12_FN2, PTU4_FN),
+ PINMUX_DATA(LGPIO3_MARK, PS6_11_FN1, PTU3_FN),
+ PINMUX_DATA(APMSLPBTN_MARK, PS6_11_FN2, PTU3_FN),
+ PINMUX_DATA(LGPIO2_MARK, PS6_10_FN1, PTU2_FN),
+ PINMUX_DATA(APMPWRBTN_MARK, PS6_10_FN2, PTU2_FN),
+ PINMUX_DATA(LGPIO1_MARK, PS6_9_FN1, PTU1_FN),
+ PINMUX_DATA(APMS5N_MARK, PS6_9_FN2, PTU1_FN),
+ PINMUX_DATA(LGPIO0_MARK, PS6_8_FN1, PTU0_FN),
+ PINMUX_DATA(APMS3N_MARK, PS6_8_FN2, PTU0_FN),
/* PTV FN */
- PINMUX_DATA(A23_MARK, PS5_7_FN1, PTV7_FN),
- PINMUX_DATA(TEND0_MARK, PS5_7_FN2, PTV7_FN),
- PINMUX_DATA(A22_MARK, PS5_6_FN1, PTV6_FN),
- PINMUX_DATA(DREQ1_MARK, PS5_6_FN2, PTV6_FN),
- PINMUX_DATA(A21_MARK, PS5_5_FN1, PTV5_FN),
- PINMUX_DATA(DACK1_MARK, PS5_5_FN2, PTV5_FN),
- PINMUX_DATA(A20_MARK, PS5_4_FN1, PTV4_FN),
- PINMUX_DATA(TEND1_MARK, PS5_4_FN2, PTV4_FN),
- PINMUX_DATA(A19_MARK, PTV3_FN),
- PINMUX_DATA(A18_MARK, PTV2_FN),
- PINMUX_DATA(A17_MARK, PTV1_FN),
- PINMUX_DATA(A16_MARK, PTV0_FN),
+ PINMUX_DATA(A23_MARK, PS6_7_FN1, PTV7_FN),
+ PINMUX_DATA(COM2_RI_MARK, PS6_7_FN2, PTV7_FN),
+ PINMUX_DATA(A22_MARK, PS6_6_FN1, PTV6_FN),
+ PINMUX_DATA(R_SPI_MOSI_MARK, PS6_6_FN2, PTV6_FN),
+ PINMUX_DATA(A21_MARK, PS6_5_FN1, PTV5_FN),
+ PINMUX_DATA(R_SPI_MISO_MARK, PS6_5_FN2, PTV5_FN),
+ PINMUX_DATA(A20_MARK, PS6_4_FN1, PTV4_FN),
+ PINMUX_DATA(R_SPI_RSPCK_MARK, PS6_4_FN2, PTV4_FN),
+ PINMUX_DATA(A19_MARK, PS6_3_FN1, PTV3_FN),
+ PINMUX_DATA(R_SPI_SSL0_MARK, PS6_3_FN2, PTV3_FN),
+ PINMUX_DATA(A18_MARK, PS6_2_FN1, PTV2_FN),
+ PINMUX_DATA(R_SPI_SSL1_MARK, PS6_2_FN2, PTV2_FN),
+ PINMUX_DATA(A17_MARK, PS6_1_FN1, PTV1_FN),
+ PINMUX_DATA(EVENT7_MARK, PS6_1_FN2, PTV1_FN),
+ PINMUX_DATA(A16_MARK, PS6_0_FN1, PTV0_FN),
+ PINMUX_DATA(EVENT6_MARK, PS6_0_FN1, PTV0_FN),
/* PTW FN */
- PINMUX_DATA(A15_MARK, PTW7_FN),
- PINMUX_DATA(A14_MARK, PTW6_FN),
- PINMUX_DATA(A13_MARK, PTW5_FN),
- PINMUX_DATA(A12_MARK, PTW4_FN),
- PINMUX_DATA(A11_MARK, PTW3_FN),
- PINMUX_DATA(A10_MARK, PTW2_FN),
- PINMUX_DATA(A9_MARK, PTW1_FN),
- PINMUX_DATA(A8_MARK, PTW0_FN),
+ PINMUX_DATA(A15_MARK, PS7_15_FN1, PTW7_FN),
+ PINMUX_DATA(EVENT5_MARK, PS7_15_FN2, PTW7_FN),
+ PINMUX_DATA(A14_MARK, PS7_14_FN1, PTW6_FN),
+ PINMUX_DATA(EVENT4_MARK, PS7_14_FN2, PTW6_FN),
+ PINMUX_DATA(A13_MARK, PS7_13_FN1, PTW5_FN),
+ PINMUX_DATA(EVENT3_MARK, PS7_13_FN2, PTW5_FN),
+ PINMUX_DATA(A12_MARK, PS7_12_FN1, PTW4_FN),
+ PINMUX_DATA(EVENT2_MARK, PS7_12_FN2, PTW4_FN),
+ PINMUX_DATA(A11_MARK, PS7_11_FN1, PTW3_FN),
+ PINMUX_DATA(EVENT1_MARK, PS7_11_FN2, PTW3_FN),
+ PINMUX_DATA(A10_MARK, PS7_10_FN1, PTW2_FN),
+ PINMUX_DATA(EVENT0_MARK, PS7_10_FN2, PTW2_FN),
+ PINMUX_DATA(A9_MARK, PS7_9_FN1, PTW1_FN),
+ PINMUX_DATA(CTS4_MARK, PS7_9_FN2, PTW1_FN),
+ PINMUX_DATA(A8_MARK, PS7_8_FN1, PTW0_FN),
+ PINMUX_DATA(CTS2_MARK, PS7_8_FN2, PTW0_FN),
/* PTX FN */
- PINMUX_DATA(A7_MARK, PTX7_FN),
- PINMUX_DATA(A6_MARK, PTX6_FN),
- PINMUX_DATA(A5_MARK, PTX5_FN),
- PINMUX_DATA(A4_MARK, PTX4_FN),
+ PINMUX_DATA(A7_MARK, PS7_7_FN1, PTX7_FN),
+ PINMUX_DATA(RTS2_MARK, PS7_7_FN2, PTX7_FN),
+ PINMUX_DATA(A6_MARK, PS7_6_FN1, PTX6_FN),
+ PINMUX_DATA(SIM_D_MARK, PS7_6_FN2, PTX6_FN),
+ PINMUX_DATA(A5_MARK, PS7_5_FN1, PTX5_FN),
+ PINMUX_DATA(SIM_CLK_MARK, PS7_5_FN2, PTX5_FN),
+ PINMUX_DATA(A4_MARK, PS7_4_FN1, PTX4_FN),
+ PINMUX_DATA(SIM_RST_MARK, PS7_4_FN2, PTX4_FN),
PINMUX_DATA(A3_MARK, PTX3_FN),
PINMUX_DATA(A2_MARK, PTX2_FN),
PINMUX_DATA(A1_MARK, PTX1_FN),
@@ -954,6 +1093,24 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(D2_MARK, PTY2_FN),
PINMUX_DATA(D1_MARK, PTY1_FN),
PINMUX_DATA(D0_MARK, PTY0_FN),
+
+ /* PTZ FN */
+ PINMUX_DATA(MMCDAT7_MARK, PS8_15_FN1, PTZ7_FN),
+ PINMUX_DATA(ON_DQ7_MARK, PS8_15_FN2, PTZ7_FN),
+ PINMUX_DATA(MMCDAT6_MARK, PS8_14_FN1, PTZ6_FN),
+ PINMUX_DATA(ON_DQ6_MARK, PS8_14_FN2, PTZ6_FN),
+ PINMUX_DATA(MMCDAT5_MARK, PS8_13_FN1, PTZ5_FN),
+ PINMUX_DATA(ON_DQ5_MARK, PS8_13_FN2, PTZ5_FN),
+ PINMUX_DATA(MMCDAT4_MARK, PS8_12_FN1, PTZ4_FN),
+ PINMUX_DATA(ON_DQ4_MARK, PS8_12_FN2, PTZ4_FN),
+ PINMUX_DATA(MMCDAT3_MARK, PS8_11_FN1, PTZ3_FN),
+ PINMUX_DATA(ON_DQ3_MARK, PS8_11_FN2, PTZ3_FN),
+ PINMUX_DATA(MMCDAT2_MARK, PS8_10_FN1, PTZ2_FN),
+ PINMUX_DATA(ON_DQ2_MARK, PS8_10_FN2, PTZ2_FN),
+ PINMUX_DATA(MMCDAT1_MARK, PS8_9_FN1, PTZ1_FN),
+ PINMUX_DATA(ON_DQ1_MARK, PS8_9_FN2, PTZ1_FN),
+ PINMUX_DATA(MMCDAT0_MARK, PS8_8_FN1, PTZ0_FN),
+ PINMUX_DATA(ON_DQ0_MARK, PS8_8_FN2, PTZ0_FN),
};
static struct pinmux_gpio pinmux_gpios[] = {
@@ -1048,7 +1205,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTI0, PTI0_DATA),
/* PTJ */
- PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
PINMUX_GPIO(GPIO_PTJ4, PTJ4_DATA),
@@ -1068,7 +1224,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
/* PTL */
- PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
@@ -1078,6 +1233,7 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
/* PTM */
+ PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
@@ -1087,7 +1243,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
/* PTN */
- PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
@@ -1107,6 +1262,7 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTO0, PTO0_DATA),
/* PTP */
+ PINMUX_GPIO(GPIO_PTP7, PTP7_DATA),
PINMUX_GPIO(GPIO_PTP6, PTP6_DATA),
PINMUX_GPIO(GPIO_PTP5, PTP5_DATA),
PINMUX_GPIO(GPIO_PTP4, PTP4_DATA),
@@ -1145,6 +1301,8 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
/* PTT */
+ PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
+ PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
@@ -1212,54 +1370,35 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
- /* PTA (mobule: LBSC, CPG, LPC) */
+ /* PTA (mobule: LBSC, RGMII) */
PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
PINMUX_GPIO(GPIO_FN_WE1, WE1_MARK),
PINMUX_GPIO(GPIO_FN_RDY, RDY_MARK),
- PINMUX_GPIO(GPIO_FN_MD10, MD10_MARK),
- PINMUX_GPIO(GPIO_FN_MD9, MD9_MARK),
- PINMUX_GPIO(GPIO_FN_MD8, MD8_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO7, LGPIO7_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO6, LGPIO6_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO5, LGPIO5_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO4, LGPIO4_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO3, LGPIO3_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO2, LGPIO2_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO1, LGPIO1_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO0, LGPIO0_MARK),
-
- /* PTB (mobule: LBSC, EtherC, SIM, LPC) */
- PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
- PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
- PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
- PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
- PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
- PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
- PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
- PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
PINMUX_GPIO(GPIO_FN_ET0_MDC, ET0_MDC_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_MDIO, ET0_MDIO_MARK),
+ PINMUX_GPIO(GPIO_FN_ET0_MDIO, ET0_MDC_MARK),
PINMUX_GPIO(GPIO_FN_ET1_MDC, ET1_MDC_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_MDIO, ET1_MDIO_MARK),
- PINMUX_GPIO(GPIO_FN_WPSZ1, WPSZ1_MARK),
- PINMUX_GPIO(GPIO_FN_WPSZ0, WPSZ0_MARK),
- PINMUX_GPIO(GPIO_FN_FWID, FWID_MARK),
- PINMUX_GPIO(GPIO_FN_FLSHSZ, FLSHSZ_MARK),
- PINMUX_GPIO(GPIO_FN_LPC_SPIEN, LPC_SPIEN_MARK),
- PINMUX_GPIO(GPIO_FN_BASEL, BASEL_MARK),
-
- /* PTC (mobule: SD) */
- PINMUX_GPIO(GPIO_FN_SD_WP, SD_WP_MARK),
- PINMUX_GPIO(GPIO_FN_SD_CD, SD_CD_MARK),
- PINMUX_GPIO(GPIO_FN_SD_CLK, SD_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SD_CMD, SD_CMD_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D3, SD_D3_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D2, SD_D2_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D1, SD_D1_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D0, SD_D0_MARK),
+ PINMUX_GPIO(GPIO_FN_ET1_MDIO, ET1_MDC_MARK),
- /* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+ /* PTB (mobule: INTC, ONFI, TMU) */
+ PINMUX_GPIO(GPIO_FN_IRQ15, IRQ15_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ14, IRQ14_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ13, IRQ13_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ12, IRQ12_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ11, IRQ11_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ10, IRQ10_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ9, IRQ9_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ8, IRQ8_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NRE, ON_NRE_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NWE, ON_NWE_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NWP, ON_NWP_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NCE0, ON_NCE0_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_R_B0, ON_R_B0_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_ALE, ON_ALE_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_CLE, ON_CLE_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
+
+ /* PTC (mobule: IRQ, PWMU) */
PINMUX_GPIO(GPIO_FN_IRQ7, IRQ7_MARK),
PINMUX_GPIO(GPIO_FN_IRQ6, IRQ6_MARK),
PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
@@ -1268,80 +1407,102 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
- PINMUX_GPIO(GPIO_FN_MD6, MD6_MARK),
- PINMUX_GPIO(GPIO_FN_MD5, MD5_MARK),
- PINMUX_GPIO(GPIO_FN_MD3, MD3_MARK),
- PINMUX_GPIO(GPIO_FN_MD2, MD2_MARK),
- PINMUX_GPIO(GPIO_FN_MD1, MD1_MARK),
- PINMUX_GPIO(GPIO_FN_MD0, MD0_MARK),
- PINMUX_GPIO(GPIO_FN_ADTRG1, ADTRG1_MARK),
- PINMUX_GPIO(GPIO_FN_ADTRG0, ADTRG0_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU0, PWMU0_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU1, PWMU1_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU2, PWMU2_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU3, PWMU3_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU4, PWMU4_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU5, PWMU5_MARK),
+
+ /* PTD (mobule: SPI0, DMAC) */
+ PINMUX_GPIO(GPIO_FN_SP0_MOSI, SP0_MOSI_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_MISO, SP0_MISO_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SCK, SP0_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SCK_FB, SP0_SCK_FB_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS0, SP0_SS0_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS1, SP0_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS2, SP0_SS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS3, SP0_SS3_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
- /* PTE (mobule: EtherC) */
- PINMUX_GPIO(GPIO_FN_ET0_CRS_DV, ET0_CRS_DV_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_TXD1, ET0_TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_TXD0, ET0_TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_TX_EN, ET0_TX_EN_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_REF_CLK, ET0_REF_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_RXD1, ET0_RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_RXD0, ET0_RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_RX_ER, ET0_RX_ER_MARK),
-
- /* PTF (mobule: EtherC) */
- PINMUX_GPIO(GPIO_FN_ET1_CRS_DV, ET1_CRS_DV_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_TXD1, ET1_TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_TXD0, ET1_TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_TX_EN, ET1_TX_EN_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_REF_CLK, ET1_REF_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_RXD1, ET1_RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_RXD0, ET1_RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_RX_ER, ET1_RX_ER_MARK),
-
- /* PTG (mobule: SYSTEM, PWMX, LPC) */
- PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
- PINMUX_GPIO(GPIO_FN_PWX0, PWX0_MARK),
- PINMUX_GPIO(GPIO_FN_PWX1, PWX1_MARK),
- PINMUX_GPIO(GPIO_FN_PWX2, PWX2_MARK),
- PINMUX_GPIO(GPIO_FN_PWX3, PWX3_MARK),
+ /* PTE (mobule: RMII) */
+ PINMUX_GPIO(GPIO_FN_RMII0_CRS_DV, RMII0_CRS_DV_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_TXD1, RMII0_TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_TXD0, RMII0_TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_TXEN, RMII0_TXEN_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_REFCLK, RMII0_REFCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_RXD1, RMII0_RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_RXD0, RMII0_RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_RX_ER, RMII0_RX_ER_MARK),
+
+ /* PTF (mobule: RMII, SerMux) */
+ PINMUX_GPIO(GPIO_FN_RMII1_CRS_DV, RMII1_CRS_DV_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_TXD1, RMII1_TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_TXD0, RMII1_TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_TXEN, RMII1_TXEN_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_REFCLK, RMII1_REFCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_RXD1, RMII1_RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_RXD0, RMII1_RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_RX_ER, RMII1_RX_ER_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_RI, RAC_RI_MARK),
+
+ /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+ PINMUX_GPIO(GPIO_FN_BOOTFMS, BOOTFMS_MARK),
+ PINMUX_GPIO(GPIO_FN_BOOTWP, BOOTWP_MARK),
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
PINMUX_GPIO(GPIO_FN_SERIRQ, SERIRQ_MARK),
- PINMUX_GPIO(GPIO_FN_CLKRUN, CLKRUN_MARK),
+ PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
PINMUX_GPIO(GPIO_FN_LPCPD, LPCPD_MARK),
PINMUX_GPIO(GPIO_FN_LDRQ, LDRQ_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCCLK, MMCCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCCMD, MMCCMD_MARK),
- /* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
- PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
- PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
- PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+ /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
PINMUX_GPIO(GPIO_FN_SP1_MOSI, SP1_MOSI_MARK),
PINMUX_GPIO(GPIO_FN_SP1_MISO, SP1_MISO_MARK),
PINMUX_GPIO(GPIO_FN_SP1_SCK, SP1_SCK_MARK),
PINMUX_GPIO(GPIO_FN_SP1_SCK_FB, SP1_SCK_FB_MARK),
PINMUX_GPIO(GPIO_FN_SP1_SS0, SP1_SS0_MARK),
PINMUX_GPIO(GPIO_FN_SP1_SS1, SP1_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_SP0_SS1, SP0_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_WP, WP_MARK),
+ PINMUX_GPIO(GPIO_FN_FMS0, FMS0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_ADTRG1, ADTRG1_MARK),
+ PINMUX_GPIO(GPIO_FN_ADTRG0, ADTRG0_MARK),
- /* PTI (mobule: INTC) */
- PINMUX_GPIO(GPIO_FN_IRQ15, IRQ15_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ14, IRQ14_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ13, IRQ13_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ12, IRQ12_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ11, IRQ11_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ10, IRQ10_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ9, IRQ9_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ8, IRQ8_MARK),
+ /* PTI (mobule: LBSC, SDHI) */
+ PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+ PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+ PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+ PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+ PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+ PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+ PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+ PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_WP, SD_WP_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_CD, SD_CD_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_CLK, SD_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_CMD, SD_CMD_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D3, SD_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D2, SD_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D1, SD_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D0, SD_D0_MARK),
/* PTJ (mobule: SCIF234, SERMUX) */
- PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
- PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
- PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_TXD, COM1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_RXD, COM1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_RTS, COM1_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_CTS, COM1_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS4, RTS4_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
- /* PTK (mobule: SERMUX) */
+ /* PTK (mobule: SERMUX, LBSC, SCIF) */
PINMUX_GPIO(GPIO_FN_COM2_TXD, COM2_TXD_MARK),
PINMUX_GPIO(GPIO_FN_COM2_RXD, COM2_RXD_MARK),
PINMUX_GPIO(GPIO_FN_COM2_RTS, COM2_RTS_MARK),
@@ -1349,62 +1510,65 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_COM2_DTR, COM2_DTR_MARK),
PINMUX_GPIO(GPIO_FN_COM2_DSR, COM2_DSR_MARK),
PINMUX_GPIO(GPIO_FN_COM2_DCD, COM2_DCD_MARK),
- PINMUX_GPIO(GPIO_FN_COM2_RI, COM2_RI_MARK),
+ PINMUX_GPIO(GPIO_FN_CLKOUT, CLKOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
- /* PTL (mobule: SERMUX) */
- PINMUX_GPIO(GPIO_FN_RAC_TXD, RAC_TXD_MARK),
+ /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
PINMUX_GPIO(GPIO_FN_RAC_RXD, RAC_RXD_MARK),
PINMUX_GPIO(GPIO_FN_RAC_RTS, RAC_RTS_MARK),
PINMUX_GPIO(GPIO_FN_RAC_CTS, RAC_CTS_MARK),
PINMUX_GPIO(GPIO_FN_RAC_DTR, RAC_DTR_MARK),
PINMUX_GPIO(GPIO_FN_RAC_DSR, RAC_DSR_MARK),
PINMUX_GPIO(GPIO_FN_RAC_DCD, RAC_DCD_MARK),
- PINMUX_GPIO(GPIO_FN_RAC_RI, RAC_RI_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_TXD, RAC_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
- /* PTM (mobule: IIC, LPC) */
+ /* PTM (mobule: LBSC, IIC) */
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+ PINMUX_GPIO(GPIO_FN_WE0, WE0_MARK),
+ PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
PINMUX_GPIO(GPIO_FN_SDA6, SDA6_MARK),
PINMUX_GPIO(GPIO_FN_SCL6, SCL6_MARK),
PINMUX_GPIO(GPIO_FN_SDA7, SDA7_MARK),
PINMUX_GPIO(GPIO_FN_SCL7, SCL7_MARK),
- PINMUX_GPIO(GPIO_FN_WP, WP_MARK),
- PINMUX_GPIO(GPIO_FN_FMS0, FMS0_MARK),
- PINMUX_GPIO(GPIO_FN_FMS1, FMS1_MARK),
- /* PTN (mobule: SCIF234, EVC) */
- PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
- PINMUX_GPIO(GPIO_FN_RTS4, RTS4_MARK),
- PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
- PINMUX_GPIO(GPIO_FN_RTS2, RTS2_MARK),
- PINMUX_GPIO(GPIO_FN_CTS4, CTS4_MARK),
- PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
- PINMUX_GPIO(GPIO_FN_CTS2, CTS2_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT7, EVENT7_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT6, EVENT6_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT5, EVENT5_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT4, EVENT4_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT3, EVENT3_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT2, EVENT2_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT1, EVENT1_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT0, EVENT0_MARK),
+ /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+ PINMUX_GPIO(GPIO_FN_VBUS_EN, VBUS_EN_MARK),
+ PINMUX_GPIO(GPIO_FN_VBUS_OC, VBUS_OC_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTCK, JMCTCK_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTMS, JMCTMS_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTDO, JMCTDO_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTDI, JMCTDI_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTRST, JMCTRST_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_CLK, SGPIO1_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_LOAD, SGPIO1_LOAD_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_DI, SGPIO1_DI_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_DO, SGPIO1_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_SUB_CLKIN, SUB_CLKIN_MARK),
- /* PTO (mobule: SGPIO) */
+ /* PTO (mobule: SGPIO, SerMux) */
PINMUX_GPIO(GPIO_FN_SGPIO0_CLK, SGPIO0_CLK_MARK),
PINMUX_GPIO(GPIO_FN_SGPIO0_LOAD, SGPIO0_LOAD_MARK),
PINMUX_GPIO(GPIO_FN_SGPIO0_DI, SGPIO0_DI_MARK),
PINMUX_GPIO(GPIO_FN_SGPIO0_DO, SGPIO0_DO_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_CLK, SGPIO1_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_LOAD, SGPIO1_LOAD_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_DI, SGPIO1_DI_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_DO, SGPIO1_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_CLK, SGPIO2_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_LOAD, SGPIO2_LOAD_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_DI, SGPIO2_DI_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_DO, SGPIO2_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_TXD, COM1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_RXD, COM1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_RTS, COM1_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_CTS, COM1_CTS_MARK),
- /* PTP (mobule: JMC, SCIF234) */
- PINMUX_GPIO(GPIO_FN_JMCTCK, JMCTCK_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTMS, JMCTMS_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTDO, JMCTDO_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTDI, JMCTDI_MARK),
- PINMUX_GPIO(GPIO_FN_JMCRST, JMCRST_MARK),
- PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
- PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+ /* PTP (mobule: EVC, ADC) */
/* PTQ (mobule: LPC) */
PINMUX_GPIO(GPIO_FN_LAD3, LAD3_MARK),
@@ -1439,31 +1603,41 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_SDA3, SDA3_MARK),
PINMUX_GPIO(GPIO_FN_SCL3, SCL3_MARK),
- /* PTT (mobule: SYSTEM, PWMX) */
- PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+ /* PTT (mobule: PWMX, AUD) */
+ PINMUX_GPIO(GPIO_FN_PWMX7, PWMX7_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX6, PWMX6_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX5, PWMX5_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX4, PWMX4_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX3, PWMX3_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX2, PWMX2_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX1, PWMX1_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX0, PWMX0_MARK),
PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
- PINMUX_GPIO(GPIO_FN_PWX7, PWX7_MARK),
- PINMUX_GPIO(GPIO_FN_PWX6, PWX6_MARK),
- PINMUX_GPIO(GPIO_FN_PWX5, PWX5_MARK),
- PINMUX_GPIO(GPIO_FN_PWX4, PWX4_MARK),
-
- /* PTU (mobule: LBSC, DMAC) */
- PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
- PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
- PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
- PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
- PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
- PINMUX_GPIO(GPIO_FN_WE0, WE0_MARK),
- PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
- PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
- /* PTV (mobule: LBSC, DMAC) */
+ /* PTU (mobule: LPC, APM) */
+ PINMUX_GPIO(GPIO_FN_LGPIO7, LGPIO7_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO6, LGPIO6_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO5, LGPIO5_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO4, LGPIO4_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO3, LGPIO3_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO2, LGPIO2_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO1, LGPIO1_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO0, LGPIO0_MARK),
+ PINMUX_GPIO(GPIO_FN_APMONCTL_O, APMONCTL_O_MARK),
+ PINMUX_GPIO(GPIO_FN_APMPWBTOUT_O, APMPWBTOUT_O_MARK),
+ PINMUX_GPIO(GPIO_FN_APMSCI_O, APMSCI_O_MARK),
+ PINMUX_GPIO(GPIO_FN_APMVDDON, APMVDDON_MARK),
+ PINMUX_GPIO(GPIO_FN_APMSLPBTN, APMSLPBTN_MARK),
+ PINMUX_GPIO(GPIO_FN_APMPWRBTN, APMPWRBTN_MARK),
+ PINMUX_GPIO(GPIO_FN_APMS5N, APMS5N_MARK),
+ PINMUX_GPIO(GPIO_FN_APMS3N, APMS3N_MARK),
+
+ /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
@@ -1472,12 +1646,20 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
- PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
- PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
- PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+ PINMUX_GPIO(GPIO_FN_COM2_RI, COM2_RI_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_MOSI, R_SPI_MOSI_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_MISO, R_SPI_MISO_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_RSPCK, R_SPI_RSPCK_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_SSL0, R_SPI_SSL0_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_SSL1, R_SPI_SSL1_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT7, EVENT7_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT6, EVENT6_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_DI, VBIOS_DI_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_DO, VBIOS_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_CLK, VBIOS_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_CS, VBIOS_CS_MARK),
- /* PTW (mobule: LBSC) */
+ /* PTW (mobule: LBSC, EVC, SCIF) */
PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
@@ -1487,6 +1669,14 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT5, EVENT5_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT4, EVENT4_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT3, EVENT3_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT2, EVENT2_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT1, EVENT1_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT0, EVENT0_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS4, CTS4_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS2, CTS2_MARK),
/* PTX (mobule: LBSC) */
PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
@@ -1497,6 +1687,10 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS2, RTS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_D, SIM_D_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_CLK, SIM_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_RST, SIM_RST_MARK),
/* PTY (mobule: LBSC) */
PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
@@ -1507,18 +1701,36 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+ /* PTZ (mobule: eMMC, ONFI) */
+ PINMUX_GPIO(GPIO_FN_MMCDAT7, MMCDAT7_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT6, MMCDAT6_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT5, MMCDAT5_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT4, MMCDAT4_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT3, MMCDAT3_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT2, MMCDAT2_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT1, MMCDAT1_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT0, MMCDAT0_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ7, ON_DQ7_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ6, ON_DQ6_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ5, ON_DQ5_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ4, ON_DQ4_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ3, ON_DQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ2, ON_DQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ1, ON_DQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ0, ON_DQ0_MARK),
};
static struct pinmux_cfg_reg pinmux_config_regs[] = {
{ PINMUX_CFG_REG("PACR", 0xffec0000, 16, 2) {
- PTA7_FN, PTA7_OUT, PTA7_IN, 0,
- PTA6_FN, PTA6_OUT, PTA6_IN, 0,
- PTA5_FN, PTA5_OUT, PTA5_IN, 0,
- PTA4_FN, PTA4_OUT, PTA4_IN, 0,
- PTA3_FN, PTA3_OUT, PTA3_IN, 0,
- PTA2_FN, PTA2_OUT, PTA2_IN, 0,
- PTA1_FN, PTA1_OUT, PTA1_IN, 0,
- PTA0_FN, PTA0_OUT, PTA0_IN, 0 }
+ PTA7_FN, PTA7_OUT, PTA7_IN, PTA7_IN_PU,
+ PTA6_FN, PTA6_OUT, PTA6_IN, PTA6_IN_PU,
+ PTA5_FN, PTA5_OUT, PTA5_IN, PTA5_IN_PU,
+ PTA4_FN, PTA4_OUT, PTA4_IN, PTA4_IN_PU,
+ PTA3_FN, PTA3_OUT, PTA3_IN, PTA3_IN_PU,
+ PTA2_FN, PTA2_OUT, PTA2_IN, PTA2_IN_PU,
+ PTA1_FN, PTA1_OUT, PTA1_IN, PTA1_IN_PU,
+ PTA0_FN, PTA0_OUT, PTA0_IN, PTA0_IN_PU }
},
{ PINMUX_CFG_REG("PBCR", 0xffec0002, 16, 2) {
PTB7_FN, PTB7_OUT, PTB7_IN, 0,
@@ -1541,125 +1753,126 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
PTC0_FN, PTC0_OUT, PTC0_IN, 0 }
},
{ PINMUX_CFG_REG("PDCR", 0xffec0006, 16, 2) {
- PTD7_FN, PTD7_OUT, PTD7_IN, 0,
- PTD6_FN, PTD6_OUT, PTD6_IN, 0,
- PTD5_FN, PTD5_OUT, PTD5_IN, 0,
- PTD4_FN, PTD4_OUT, PTD4_IN, 0,
- PTD3_FN, PTD3_OUT, PTD3_IN, 0,
- PTD2_FN, PTD2_OUT, PTD2_IN, 0,
- PTD1_FN, PTD1_OUT, PTD1_IN, 0,
- PTD0_FN, PTD0_OUT, PTD0_IN, 0 }
+ PTD7_FN, PTD7_OUT, PTD7_IN, PTD7_IN_PU,
+ PTD6_FN, PTD6_OUT, PTD6_IN, PTD6_IN_PU,
+ PTD5_FN, PTD5_OUT, PTD5_IN, PTD5_IN_PU,
+ PTD4_FN, PTD4_OUT, PTD4_IN, PTD4_IN_PU,
+ PTD3_FN, PTD3_OUT, PTD3_IN, PTD3_IN_PU,
+ PTD2_FN, PTD2_OUT, PTD2_IN, PTD2_IN_PU,
+ PTD1_FN, PTD1_OUT, PTD1_IN, PTD1_IN_PU,
+ PTD0_FN, PTD0_OUT, PTD0_IN, PTD0_IN_PU }
},
{ PINMUX_CFG_REG("PECR", 0xffec0008, 16, 2) {
- PTE7_FN, PTE7_OUT, PTE7_IN, 0,
- PTE6_FN, PTE6_OUT, PTE6_IN, 0,
- PTE5_FN, PTE5_OUT, PTE5_IN, 0,
- PTE4_FN, PTE4_OUT, PTE4_IN, 0,
- PTE3_FN, PTE3_OUT, PTE3_IN, 0,
- PTE2_FN, PTE2_OUT, PTE2_IN, 0,
- PTE1_FN, PTE1_OUT, PTE1_IN, 0,
- PTE0_FN, PTE0_OUT, PTE0_IN, 0 }
+ PTE7_FN, PTE7_OUT, PTE7_IN, PTE7_IN_PU,
+ PTE6_FN, PTE6_OUT, PTE6_IN, PTE6_IN_PU,
+ PTE5_FN, PTE5_OUT, PTE5_IN, PTE5_IN_PU,
+ PTE4_FN, PTE4_OUT, PTE4_IN, PTE4_IN_PU,
+ PTE3_FN, PTE3_OUT, PTE3_IN, PTE3_IN_PU,
+ PTE2_FN, PTE2_OUT, PTE2_IN, PTE2_IN_PU,
+ PTE1_FN, PTE1_OUT, PTE1_IN, PTE1_IN_PU,
+ PTE0_FN, PTE0_OUT, PTE0_IN, PTE0_IN_PU }
},
{ PINMUX_CFG_REG("PFCR", 0xffec000a, 16, 2) {
- PTF7_FN, PTF7_OUT, PTF7_IN, 0,
- PTF6_FN, PTF6_OUT, PTF6_IN, 0,
- PTF5_FN, PTF5_OUT, PTF5_IN, 0,
- PTF4_FN, PTF4_OUT, PTF4_IN, 0,
- PTF3_FN, PTF3_OUT, PTF3_IN, 0,
- PTF2_FN, PTF2_OUT, PTF2_IN, 0,
- PTF1_FN, PTF1_OUT, PTF1_IN, 0,
- PTF0_FN, PTF0_OUT, PTF0_IN, 0 }
+ PTF7_FN, PTF7_OUT, PTF7_IN, PTF7_IN_PU,
+ PTF6_FN, PTF6_OUT, PTF6_IN, PTF6_IN_PU,
+ PTF5_FN, PTF5_OUT, PTF5_IN, PTF5_IN_PU,
+ PTF4_FN, PTF4_OUT, PTF4_IN, PTF4_IN_PU,
+ PTF3_FN, PTF3_OUT, PTF3_IN, PTF3_IN_PU,
+ PTF2_FN, PTF2_OUT, PTF2_IN, PTF2_IN_PU,
+ PTF1_FN, PTF1_OUT, PTF1_IN, PTF1_IN_PU,
+ PTF0_FN, PTF0_OUT, PTF0_IN, PTF0_IN_PU }
},
{ PINMUX_CFG_REG("PGCR", 0xffec000c, 16, 2) {
- PTG7_FN, PTG7_OUT, PTG7_IN, 0,
- PTG6_FN, PTG6_OUT, PTG6_IN, 0,
+ PTG7_FN, PTG7_OUT, PTG7_IN, PTG7_IN_PU ,
+ PTG6_FN, PTG6_OUT, PTG6_IN, PTG6_IN_PU ,
PTG5_FN, PTG5_OUT, PTG5_IN, 0,
- PTG4_FN, PTG4_OUT, PTG4_IN, 0,
+ PTG4_FN, PTG4_OUT, PTG4_IN, PTG4_IN_PU ,
PTG3_FN, PTG3_OUT, PTG3_IN, 0,
PTG2_FN, PTG2_OUT, PTG2_IN, 0,
PTG1_FN, PTG1_OUT, PTG1_IN, 0,
PTG0_FN, PTG0_OUT, PTG0_IN, 0 }
},
{ PINMUX_CFG_REG("PHCR", 0xffec000e, 16, 2) {
- PTH7_FN, PTH7_OUT, PTH7_IN, 0,
- PTH6_FN, PTH6_OUT, PTH6_IN, 0,
- PTH5_FN, PTH5_OUT, PTH5_IN, 0,
- PTH4_FN, PTH4_OUT, PTH4_IN, 0,
- PTH3_FN, PTH3_OUT, PTH3_IN, 0,
- PTH2_FN, PTH2_OUT, PTH2_IN, 0,
- PTH1_FN, PTH1_OUT, PTH1_IN, 0,
- PTH0_FN, PTH0_OUT, PTH0_IN, 0 }
+ PTH7_FN, PTH7_OUT, PTH7_IN, PTH7_IN_PU,
+ PTH6_FN, PTH6_OUT, PTH6_IN, PTH6_IN_PU,
+ PTH5_FN, PTH5_OUT, PTH5_IN, PTH5_IN_PU,
+ PTH4_FN, PTH4_OUT, PTH4_IN, PTH4_IN_PU,
+ PTH3_FN, PTH3_OUT, PTH3_IN, PTH3_IN_PU,
+ PTH2_FN, PTH2_OUT, PTH2_IN, PTH2_IN_PU,
+ PTH1_FN, PTH1_OUT, PTH1_IN, PTH1_IN_PU,
+ PTH0_FN, PTH0_OUT, PTH0_IN, PTH0_IN_PU }
},
{ PINMUX_CFG_REG("PICR", 0xffec0010, 16, 2) {
- PTI7_FN, PTI7_OUT, PTI7_IN, 0,
- PTI6_FN, PTI6_OUT, PTI6_IN, 0,
+ PTI7_FN, PTI7_OUT, PTI7_IN, PTI7_IN_PU,
+ PTI6_FN, PTI6_OUT, PTI6_IN, PTI6_IN_PU,
PTI5_FN, PTI5_OUT, PTI5_IN, 0,
- PTI4_FN, PTI4_OUT, PTI4_IN, 0,
- PTI3_FN, PTI3_OUT, PTI3_IN, 0,
- PTI2_FN, PTI2_OUT, PTI2_IN, 0,
- PTI1_FN, PTI1_OUT, PTI1_IN, 0,
- PTI0_FN, PTI0_OUT, PTI0_IN, 0 }
+ PTI4_FN, PTI4_OUT, PTI4_IN, PTI4_IN_PU,
+ PTI3_FN, PTI3_OUT, PTI3_IN, PTI3_IN_PU,
+ PTI2_FN, PTI2_OUT, PTI2_IN, PTI2_IN_PU,
+ PTI1_FN, PTI1_OUT, PTI1_IN, PTI1_IN_PU,
+ PTI0_FN, PTI0_OUT, PTI0_IN, PTI0_IN_PU }
},
{ PINMUX_CFG_REG("PJCR", 0xffec0012, 16, 2) {
- PTJ7_FN, PTJ7_OUT, PTJ7_IN, 0,
- PTJ6_FN, PTJ6_OUT, PTJ6_IN, 0,
- PTJ5_FN, PTJ5_OUT, PTJ5_IN, 0,
- PTJ4_FN, PTJ4_OUT, PTJ4_IN, 0,
- PTJ3_FN, PTJ3_OUT, PTJ3_IN, 0,
- PTJ2_FN, PTJ2_OUT, PTJ2_IN, 0,
- PTJ1_FN, PTJ1_OUT, PTJ1_IN, 0,
- PTJ0_FN, PTJ0_OUT, PTJ0_IN, 0 }
+ 0, 0, 0, 0, /* reserved: always set 1 */
+ PTJ6_FN, PTJ6_OUT, PTJ6_IN, PTJ6_IN_PU,
+ PTJ5_FN, PTJ5_OUT, PTJ5_IN, PTJ5_IN_PU,
+ PTJ4_FN, PTJ4_OUT, PTJ4_IN, PTJ4_IN_PU,
+ PTJ3_FN, PTJ3_OUT, PTJ3_IN, PTJ3_IN_PU,
+ PTJ2_FN, PTJ2_OUT, PTJ2_IN, PTJ2_IN_PU,
+ PTJ1_FN, PTJ1_OUT, PTJ1_IN, PTJ1_IN_PU,
+ PTJ0_FN, PTJ0_OUT, PTJ0_IN, PTJ0_IN_PU }
},
{ PINMUX_CFG_REG("PKCR", 0xffec0014, 16, 2) {
- PTK7_FN, PTK7_OUT, PTK7_IN, 0,
- PTK6_FN, PTK6_OUT, PTK6_IN, 0,
- PTK5_FN, PTK5_OUT, PTK5_IN, 0,
- PTK4_FN, PTK4_OUT, PTK4_IN, 0,
- PTK3_FN, PTK3_OUT, PTK3_IN, 0,
- PTK2_FN, PTK2_OUT, PTK2_IN, 0,
- PTK1_FN, PTK1_OUT, PTK1_IN, 0,
- PTK0_FN, PTK0_OUT, PTK0_IN, 0 }
+ PTK7_FN, PTK7_OUT, PTK7_IN, PTK7_IN_PU,
+ PTK6_FN, PTK6_OUT, PTK6_IN, PTK6_IN_PU,
+ PTK5_FN, PTK5_OUT, PTK5_IN, PTK5_IN_PU,
+ PTK4_FN, PTK4_OUT, PTK4_IN, PTK4_IN_PU,
+ PTK3_FN, PTK3_OUT, PTK3_IN, PTK3_IN_PU,
+ PTK2_FN, PTK2_OUT, PTK2_IN, PTK2_IN_PU,
+ PTK1_FN, PTK1_OUT, PTK1_IN, PTK1_IN_PU,
+ PTK0_FN, PTK0_OUT, PTK0_IN, PTK0_IN_PU }
},
{ PINMUX_CFG_REG("PLCR", 0xffec0016, 16, 2) {
- PTL7_FN, PTL7_OUT, PTL7_IN, 0,
- PTL6_FN, PTL6_OUT, PTL6_IN, 0,
- PTL5_FN, PTL5_OUT, PTL5_IN, 0,
- PTL4_FN, PTL4_OUT, PTL4_IN, 0,
- PTL3_FN, PTL3_OUT, PTL3_IN, 0,
- PTL2_FN, PTL2_OUT, PTL2_IN, 0,
- PTL1_FN, PTL1_OUT, PTL1_IN, 0,
- PTL0_FN, PTL0_OUT, PTL0_IN, 0 }
+ 0, 0, 0, 0, /* reserved: always set 1 */
+ PTL6_FN, PTL6_OUT, PTL6_IN, PTL6_IN_PU,
+ PTL5_FN, PTL5_OUT, PTL5_IN, PTL5_IN_PU,
+ PTL4_FN, PTL4_OUT, PTL4_IN, PTL4_IN_PU,
+ PTL3_FN, PTL3_OUT, PTL3_IN, PTL3_IN_PU,
+ PTL2_FN, PTL2_OUT, PTL2_IN, PTL2_IN_PU,
+ PTL1_FN, PTL1_OUT, PTL1_IN, PTL1_IN_PU,
+ PTL0_FN, PTL0_OUT, PTL0_IN, PTL0_IN_PU }
},
{ PINMUX_CFG_REG("PMCR", 0xffec0018, 16, 2) {
- 0, 0, 0, 0, /* reserved: always set 1 */
- PTM6_FN, PTM6_OUT, PTM6_IN, 0,
- PTM5_FN, PTM5_OUT, PTM5_IN, 0,
- PTM4_FN, PTM4_OUT, PTM4_IN, 0,
+ PTM7_FN, PTM7_OUT, PTM7_IN, PTM7_IN_PU,
+ PTM6_FN, PTM6_OUT, PTM6_IN, PTM6_IN_PU,
+ PTM5_FN, PTM5_OUT, PTM5_IN, PTM5_IN_PU,
+ PTM4_FN, PTM4_OUT, PTM4_IN, PTM4_IN_PU,
PTM3_FN, PTM3_OUT, PTM3_IN, 0,
PTM2_FN, PTM2_OUT, PTM2_IN, 0,
PTM1_FN, PTM1_OUT, PTM1_IN, 0,
PTM0_FN, PTM0_OUT, PTM0_IN, 0 }
},
{ PINMUX_CFG_REG("PNCR", 0xffec001a, 16, 2) {
- PTN7_FN, PTN7_OUT, PTN7_IN, 0,
+ 0, 0, 0, 0, /* reserved: always set 1 */
PTN6_FN, PTN6_OUT, PTN6_IN, 0,
PTN5_FN, PTN5_OUT, PTN5_IN, 0,
- PTN4_FN, PTN4_OUT, PTN4_IN, 0,
- PTN3_FN, PTN3_OUT, PTN3_IN, 0,
- PTN2_FN, PTN2_OUT, PTN2_IN, 0,
- PTN1_FN, PTN1_OUT, PTN1_IN, 0,
- PTN0_FN, PTN0_OUT, PTN0_IN, 0 }
+ PTN4_FN, PTN4_OUT, PTN4_IN, PTN4_IN_PU,
+ PTN3_FN, PTN3_OUT, PTN3_IN, PTN3_IN_PU,
+ PTN2_FN, PTN2_OUT, PTN2_IN, PTN2_IN_PU,
+ PTN1_FN, PTN1_OUT, PTN1_IN, PTN1_IN_PU,
+ PTN0_FN, PTN0_OUT, PTN0_IN, PTN0_IN_PU }
},
{ PINMUX_CFG_REG("POCR", 0xffec001c, 16, 2) {
- PTO7_FN, PTO7_OUT, PTO7_IN, 0,
- PTO6_FN, PTO6_OUT, PTO6_IN, 0,
- PTO5_FN, PTO5_OUT, PTO5_IN, 0,
- PTO4_FN, PTO4_OUT, PTO4_IN, 0,
- PTO3_FN, PTO3_OUT, PTO3_IN, 0,
- PTO2_FN, PTO2_OUT, PTO2_IN, 0,
- PTO1_FN, PTO1_OUT, PTO1_IN, 0,
- PTO0_FN, PTO0_OUT, PTO0_IN, 0 }
+ PTO7_FN, PTO7_OUT, PTO7_IN, PTO7_IN_PU,
+ PTO6_FN, PTO6_OUT, PTO6_IN, PTO6_IN_PU,
+ PTO5_FN, PTO5_OUT, PTO5_IN, PTO5_IN_PU,
+ PTO4_FN, PTO4_OUT, PTO4_IN, PTO4_IN_PU,
+ PTO3_FN, PTO3_OUT, PTO3_IN, PTO3_IN_PU,
+ PTO2_FN, PTO2_OUT, PTO2_IN, PTO2_IN_PU,
+ PTO1_FN, PTO1_OUT, PTO1_IN, PTO1_IN_PU,
+ PTO0_FN, PTO0_OUT, PTO0_IN, PTO0_IN_PU }
},
+#if 0 /* FIXME: Remove it? */
{ PINMUX_CFG_REG("PPCR", 0xffec001e, 16, 2) {
0, 0, 0, 0, /* reserved: always set 1 */
PTP6_FN, PTP6_OUT, PTP6_IN, 0,
@@ -1670,6 +1883,7 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
PTP1_FN, PTP1_OUT, PTP1_IN, 0,
PTP0_FN, PTP0_OUT, PTP0_IN, 0 }
},
+#endif
{ PINMUX_CFG_REG("PQCR", 0xffec0020, 16, 2) {
0, 0, 0, 0, /* reserved: always set 1 */
PTQ6_FN, PTQ6_OUT, PTQ6_IN, 0,
@@ -1701,14 +1915,14 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
PTS0_FN, PTS0_OUT, PTS0_IN, 0 }
},
{ PINMUX_CFG_REG("PTCR", 0xffec0026, 16, 2) {
- 0, 0, 0, 0, /* reserved: always set 1 */
- 0, 0, 0, 0, /* reserved: always set 1 */
- PTT5_FN, PTT5_OUT, PTT5_IN, 0,
- PTT4_FN, PTT4_OUT, PTT4_IN, 0,
- PTT3_FN, PTT3_OUT, PTT3_IN, 0,
- PTT2_FN, PTT2_OUT, PTT2_IN, 0,
- PTT1_FN, PTT1_OUT, PTT1_IN, 0,
- PTT0_FN, PTT0_OUT, PTT0_IN, 0 }
+ PTT7_FN, PTT7_OUT, PTT7_IN, PTO7_IN_PU,
+ PTT6_FN, PTT6_OUT, PTT6_IN, PTO6_IN_PU,
+ PTT5_FN, PTT5_OUT, PTT5_IN, PTO5_IN_PU,
+ PTT4_FN, PTT4_OUT, PTT4_IN, PTO4_IN_PU,
+ PTT3_FN, PTT3_OUT, PTT3_IN, PTO3_IN_PU,
+ PTT2_FN, PTT2_OUT, PTT2_IN, PTO2_IN_PU,
+ PTT1_FN, PTT1_OUT, PTT1_IN, PTO1_IN_PU,
+ PTT0_FN, PTT0_OUT, PTT0_IN, PTO0_IN_PU }
},
{ PINMUX_CFG_REG("PUCR", 0xffec0028, 16, 2) {
PTU7_FN, PTU7_OUT, PTU7_IN, PTU7_IN_PU,
@@ -1727,16 +1941,16 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
PTV4_FN, PTV4_OUT, PTV4_IN, PTV4_IN_PU,
PTV3_FN, PTV3_OUT, PTV3_IN, PTV3_IN_PU,
PTV2_FN, PTV2_OUT, PTV2_IN, PTV2_IN_PU,
- PTV1_FN, PTV1_OUT, PTV1_IN, PTV1_IN_PU,
- PTV0_FN, PTV0_OUT, PTV0_IN, PTV0_IN_PU }
+ PTV1_FN, PTV1_OUT, PTV1_IN, 0,
+ PTV0_FN, PTV0_OUT, PTV0_IN, 0 }
},
{ PINMUX_CFG_REG("PWCR", 0xffec002c, 16, 2) {
- PTW7_FN, PTW7_OUT, PTW7_IN, PTW7_IN_PU,
- PTW6_FN, PTW6_OUT, PTW6_IN, PTW6_IN_PU,
- PTW5_FN, PTW5_OUT, PTW5_IN, PTW5_IN_PU,
- PTW4_FN, PTW4_OUT, PTW4_IN, PTW4_IN_PU,
- PTW3_FN, PTW3_OUT, PTW3_IN, PTW3_IN_PU,
- PTW2_FN, PTW2_OUT, PTW2_IN, PTW2_IN_PU,
+ PTW7_FN, PTW7_OUT, PTW7_IN, 0,
+ PTW6_FN, PTW6_OUT, PTW6_IN, 0,
+ PTW5_FN, PTW5_OUT, PTW5_IN, 0,
+ PTW4_FN, PTW4_OUT, PTW4_IN, 0,
+ PTW3_FN, PTW3_OUT, PTW3_IN, 0,
+ PTW2_FN, PTW2_OUT, PTW2_IN, 0,
PTW1_FN, PTW1_OUT, PTW1_IN, PTW1_IN_PU,
PTW0_FN, PTW0_OUT, PTW0_IN, PTW0_IN_PU }
},
@@ -1761,32 +1975,32 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
PTY0_FN, PTY0_OUT, PTY0_IN, PTY0_IN_PU }
},
{ PINMUX_CFG_REG("PZCR", 0xffec0032, 16, 2) {
- 0, PTZ7_OUT, PTZ7_IN, 0,
- 0, PTZ6_OUT, PTZ6_IN, 0,
- 0, PTZ5_OUT, PTZ5_IN, 0,
- 0, PTZ4_OUT, PTZ4_IN, 0,
- 0, PTZ3_OUT, PTZ3_IN, 0,
- 0, PTZ2_OUT, PTZ2_IN, 0,
- 0, PTZ1_OUT, PTZ1_IN, 0,
- 0, PTZ0_OUT, PTZ0_IN, 0 }
+ PTZ7_FN, PTZ7_OUT, PTZ7_IN, 0,
+ PTZ6_FN, PTZ6_OUT, PTZ6_IN, 0,
+ PTZ5_FN, PTZ5_OUT, PTZ5_IN, 0,
+ PTZ4_FN, PTZ4_OUT, PTZ4_IN, 0,
+ PTZ3_FN, PTZ3_OUT, PTZ3_IN, 0,
+ PTZ2_FN, PTZ2_OUT, PTZ2_IN, 0,
+ PTZ1_FN, PTZ1_OUT, PTZ1_IN, 0,
+ PTZ0_FN, PTZ0_OUT, PTZ0_IN, 0 }
},
{ PINMUX_CFG_REG("PSEL0", 0xffec0070, 16, 1) {
- PS0_15_FN3, PS0_15_FN1,
- PS0_14_FN3, PS0_14_FN1,
- PS0_13_FN3, PS0_13_FN1,
- PS0_12_FN3, PS0_12_FN1,
- 0, 0,
- 0, 0,
+ PS0_15_FN1, PS0_15_FN2,
+ PS0_14_FN1, PS0_14_FN2,
+ PS0_13_FN1, PS0_13_FN2,
+ PS0_12_FN1, PS0_12_FN2,
+ PS0_11_FN1, PS0_11_FN2,
+ PS0_10_FN1, PS0_10_FN2,
+ PS0_9_FN1, PS0_9_FN2,
+ PS0_8_FN1, PS0_8_FN2,
+ PS0_7_FN1, PS0_7_FN2,
+ PS0_6_FN1, PS0_6_FN2,
+ PS0_5_FN1, PS0_5_FN2,
+ PS0_4_FN1, PS0_4_FN2,
+ PS0_3_FN1, PS0_3_FN2,
+ PS0_2_FN1, PS0_2_FN2,
0, 0,
- 0, 0,
- PS0_7_FN2, PS0_7_FN1,
- PS0_6_FN2, PS0_6_FN1,
- PS0_5_FN2, PS0_5_FN1,
- PS0_4_FN2, PS0_4_FN1,
- PS0_3_FN2, PS0_3_FN1,
- PS0_2_FN2, PS0_2_FN1,
- PS0_1_FN2, PS0_1_FN1,
0, 0, }
},
{ PINMUX_CFG_REG("PSEL1", 0xffec0072, 16, 1) {
@@ -1795,73 +2009,136 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
0, 0,
0, 0,
0, 0,
+ PS1_10_FN1, PS1_10_FN2,
+ PS1_9_FN1, PS1_9_FN2,
+ PS1_8_FN1, PS1_8_FN2,
0, 0,
0, 0,
0, 0,
- PS1_7_FN1, PS1_7_FN3,
- PS1_6_FN1, PS1_6_FN3,
- 0, 0,
- 0, 0,
0, 0,
0, 0,
+ PS1_2_FN1, PS1_2_FN2,
0, 0,
0, 0, }
},
{ PINMUX_CFG_REG("PSEL2", 0xffec0074, 16, 1) {
0, 0,
0, 0,
- PS2_13_FN3, PS2_13_FN1,
- PS2_12_FN3, PS2_12_FN1,
+ PS2_13_FN1, PS2_13_FN2,
+ PS2_12_FN1, PS2_12_FN2,
0, 0,
0, 0,
0, 0,
0, 0,
+ PS2_7_FN1, PS2_7_FN2,
+ PS2_6_FN1, PS2_6_FN2,
+ PS2_5_FN1, PS2_5_FN2,
+ PS2_4_FN1, PS2_4_FN2,
0, 0,
+ PS2_2_FN1, PS2_2_FN2,
0, 0,
+ 0, 0, }
+ },
+ { PINMUX_CFG_REG("PSEL3", 0xffec0076, 16, 1) {
+ PS3_15_FN1, PS3_15_FN2,
+ PS3_14_FN1, PS3_14_FN2,
+ PS3_13_FN1, PS3_13_FN2,
+ PS3_12_FN1, PS3_12_FN2,
+ PS3_11_FN1, PS3_11_FN2,
+ PS3_10_FN1, PS3_10_FN2,
+ PS3_9_FN1, PS3_9_FN2,
+ PS3_8_FN1, PS3_8_FN2,
+ PS3_7_FN1, PS3_7_FN2,
0, 0,
0, 0,
0, 0,
0, 0,
- PS2_1_FN1, PS2_1_FN2,
- PS2_0_FN1, PS2_0_FN2, }
+ PS3_2_FN1, PS3_2_FN2,
+ PS3_1_FN1, PS3_1_FN2,
+ 0, 0, }
},
+
{ PINMUX_CFG_REG("PSEL4", 0xffec0078, 16, 1) {
- PS4_15_FN2, PS4_15_FN1,
- PS4_14_FN2, PS4_14_FN1,
- PS4_13_FN2, PS4_13_FN1,
- PS4_12_FN2, PS4_12_FN1,
- PS4_11_FN2, PS4_11_FN1,
- PS4_10_FN2, PS4_10_FN1,
- PS4_9_FN2, PS4_9_FN1,
0, 0,
+ PS4_14_FN1, PS4_14_FN2,
+ PS4_13_FN1, PS4_13_FN2,
+ PS4_12_FN1, PS4_12_FN2,
0, 0,
+ PS4_10_FN1, PS4_10_FN2,
+ PS4_9_FN1, PS4_9_FN2,
+ PS4_8_FN1, PS4_8_FN2,
0, 0,
0, 0,
0, 0,
- PS4_3_FN2, PS4_3_FN1,
- PS4_2_FN2, PS4_2_FN1,
- PS4_1_FN2, PS4_1_FN1,
- PS4_0_FN2, PS4_0_FN1, }
+ PS4_4_FN1, PS4_4_FN2,
+ PS4_3_FN1, PS4_3_FN2,
+ PS4_2_FN1, PS4_2_FN2,
+ PS4_1_FN1, PS4_1_FN2,
+ PS4_0_FN1, PS4_0_FN2, }
},
{ PINMUX_CFG_REG("PSEL5", 0xffec007a, 16, 1) {
0, 0,
0, 0,
0, 0,
0, 0,
- 0, 0,
- 0, 0,
+ PS5_11_FN1, PS5_11_FN2,
+ PS5_10_FN1, PS5_10_FN2,
PS5_9_FN1, PS5_9_FN2,
PS5_8_FN1, PS5_8_FN2,
PS5_7_FN1, PS5_7_FN2,
PS5_6_FN1, PS5_6_FN2,
PS5_5_FN1, PS5_5_FN2,
+ PS5_4_FN1, PS5_4_FN2,
+ PS5_3_FN1, PS5_3_FN2,
+ PS5_2_FN1, PS5_2_FN2,
+ 0, 0,
+ 0, 0, }
+ },
+ { PINMUX_CFG_REG("PSEL6", 0xffec007c, 16, 1) {
+ PS6_15_FN1, PS6_15_FN2,
+ PS6_14_FN1, PS6_14_FN2,
+ PS6_13_FN1, PS6_13_FN2,
+ PS6_12_FN1, PS6_12_FN2,
+ PS6_11_FN1, PS6_11_FN2,
+ PS6_10_FN1, PS6_10_FN2,
+ PS6_9_FN1, PS6_9_FN2,
+ PS6_8_FN1, PS6_8_FN2,
+ PS6_7_FN1, PS6_7_FN2,
+ PS6_6_FN1, PS6_6_FN2,
+ PS6_5_FN1, PS6_5_FN2,
+ PS6_4_FN1, PS6_4_FN2,
+ PS6_3_FN1, PS6_3_FN2,
+ PS6_2_FN1, PS6_2_FN2,
+ PS6_1_FN1, PS6_1_FN2,
+ PS6_0_FN1, PS6_0_FN2, }
+ },
+ { PINMUX_CFG_REG("PSEL7", 0xffec0082, 16, 1) {
+ PS7_15_FN1, PS7_15_FN2,
+ PS7_14_FN1, PS7_14_FN2,
+ PS7_13_FN1, PS7_13_FN2,
+ PS7_12_FN1, PS7_12_FN2,
+ PS7_11_FN1, PS7_11_FN2,
+ PS7_10_FN1, PS7_10_FN2,
+ PS7_9_FN1, PS7_9_FN2,
+ PS7_8_FN1, PS7_8_FN2,
+ PS7_7_FN1, PS7_7_FN2,
+ PS7_6_FN1, PS7_6_FN2,
+ PS7_5_FN1, PS7_5_FN2,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0, }
},
- { PINMUX_CFG_REG("PSEL6", 0xffec007c, 16, 1) {
+ { PINMUX_CFG_REG("PSEL8", 0xffec0084, 16, 1) {
+ PS8_15_FN1, PS8_15_FN2,
+ PS8_14_FN1, PS8_14_FN2,
+ PS8_13_FN1, PS8_13_FN2,
+ PS8_12_FN1, PS8_12_FN2,
+ PS8_11_FN1, PS8_11_FN2,
+ PS8_10_FN1, PS8_10_FN2,
+ PS8_9_FN1, PS8_9_FN2,
+ PS8_8_FN1, PS8_8_FN2,
0, 0,
0, 0,
0, 0,
@@ -1869,15 +2146,7 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
0, 0,
0, 0,
0, 0,
- 0, 0,
- PS6_7_FN_AN, PS6_7_FN_EV,
- PS6_6_FN_AN, PS6_6_FN_EV,
- PS6_5_FN_AN, PS6_5_FN_EV,
- PS6_4_FN_AN, PS6_4_FN_EV,
- PS6_3_FN_AN, PS6_3_FN_EV,
- PS6_2_FN_AN, PS6_2_FN_EV,
- PS6_1_FN_AN, PS6_1_FN_EV,
- PS6_0_FN_AN, PS6_0_FN_EV, }
+ 0, 0, }
},
{}
};
@@ -1920,7 +2189,7 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA }
},
{ PINMUX_DATA_REG("PJDR", 0xffec0046, 8) {
- PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+ 0, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
},
{ PINMUX_DATA_REG("PKDR", 0xffec0048, 8) {
@@ -1928,15 +2197,15 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
},
{ PINMUX_DATA_REG("PLDR", 0xffec004a, 8) {
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ 0, PTL6_DATA, PTL5_DATA, PTL4_DATA,
PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
},
{ PINMUX_DATA_REG("PMDR", 0xffec004c, 8) {
- 0, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
},
{ PINMUX_DATA_REG("PNDR", 0xffec004e, 8) {
- PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ 0, PTN6_DATA, PTN5_DATA, PTN4_DATA,
PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
},
{ PINMUX_DATA_REG("PODR", 0xffec0050, 8) {
@@ -1944,7 +2213,7 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA }
},
{ PINMUX_DATA_REG("PPDR", 0xffec0052, 8) {
- 0, PTP6_DATA, PTP5_DATA, PTP4_DATA,
+ PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA }
},
{ PINMUX_DATA_REG("PQDR", 0xffec0054, 8) {
@@ -1960,7 +2229,7 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
},
{ PINMUX_DATA_REG("PTDR", 0xffec005a, 8) {
- 0, 0, PTT5_DATA, PTT4_DATA,
+ PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
},
{ PINMUX_DATA_REG("PUDR", 0xffec005c, 8) {
@@ -2000,8 +2269,8 @@ static struct pinmux_info sh7757_pinmux_info = {
.mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
- .first_gpio = GPIO_PTA7,
- .last_gpio = GPIO_FN_D0,
+ .first_gpio = GPIO_PTA0,
+ .last_gpio = GPIO_FN_ON_DQ0,
.gpios = pinmux_gpios,
.cfg_regs = pinmux_config_regs,
@@ -2015,5 +2284,4 @@ static int __init plat_pinmux_setup(void)
{
return register_pinmux(&sh7757_pinmux_info);
}
-
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c b/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c
new file mode 100644
index 000000000000..aaa5338abbff
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c
@@ -0,0 +1,587 @@
+/*
+ * SH-X3 prototype CPU pinmux
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/shx3.h>
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+
+ PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ PA7_IN, PA6_IN, PA5_IN, PA4_IN,
+ PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+ PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+ PB3_IN, PB2_IN, PB1_IN, PB0_IN,
+ PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+ PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+ PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+ PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+ PE7_IN, PE6_IN, PE5_IN, PE4_IN,
+ PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+ PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+ PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+ PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+ PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+
+ PH5_IN, PH4_IN,
+ PH3_IN, PH2_IN, PH1_IN, PH0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_INPUT_PULLUP_BEGIN,
+ PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
+ PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
+ PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
+ PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
+ PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
+ PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
+ PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
+ PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
+ PE7_IN_PU, PE6_IN_PU, PE5_IN_PU, PE4_IN_PU,
+ PE3_IN_PU, PE2_IN_PU, PE1_IN_PU, PE0_IN_PU,
+ PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
+ PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
+ PG7_IN_PU, PG6_IN_PU, PG5_IN_PU, PG4_IN_PU,
+ PG3_IN_PU, PG2_IN_PU, PG1_IN_PU, PG0_IN_PU,
+
+ PH5_IN_PU, PH4_IN_PU,
+ PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
+ PINMUX_INPUT_PULLUP_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
+ PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+ PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+ PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
+ PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+ PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+ PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+ PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+ PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
+ PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+ PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+ PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+ PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+ PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+
+ PH5_OUT, PH4_OUT,
+ PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PA7_FN, PA6_FN, PA5_FN, PA4_FN,
+ PA3_FN, PA2_FN, PA1_FN, PA0_FN,
+ PB7_FN, PB6_FN, PB5_FN, PB4_FN,
+ PB3_FN, PB2_FN, PB1_FN, PB0_FN,
+ PC7_FN, PC6_FN, PC5_FN, PC4_FN,
+ PC3_FN, PC2_FN, PC1_FN, PC0_FN,
+ PD7_FN, PD6_FN, PD5_FN, PD4_FN,
+ PD3_FN, PD2_FN, PD1_FN, PD0_FN,
+ PE7_FN, PE6_FN, PE5_FN, PE4_FN,
+ PE3_FN, PE2_FN, PE1_FN, PE0_FN,
+ PF7_FN, PF6_FN, PF5_FN, PF4_FN,
+ PF3_FN, PF2_FN, PF1_FN, PF0_FN,
+ PG7_FN, PG6_FN, PG5_FN, PG4_FN,
+ PG3_FN, PG2_FN, PG1_FN, PG0_FN,
+
+ PH5_FN, PH4_FN,
+ PH3_FN, PH2_FN, PH1_FN, PH0_FN,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+
+ D31_MARK, D30_MARK, D29_MARK, D28_MARK, D27_MARK, D26_MARK,
+ D25_MARK, D24_MARK, D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+ D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+
+ BACK_MARK, BREQ_MARK,
+ WE3_MARK, WE2_MARK,
+ CS6_MARK, CS5_MARK, CS4_MARK,
+ CLKOUTENB_MARK,
+
+ DACK3_MARK, DACK2_MARK, DACK1_MARK, DACK0_MARK,
+ DREQ3_MARK, DREQ2_MARK, DREQ1_MARK, DREQ0_MARK,
+
+ IRQ3_MARK, IRQ2_MARK, IRQ1_MARK, IRQ0_MARK,
+
+ DRAK3_MARK, DRAK2_MARK, DRAK1_MARK, DRAK0_MARK,
+
+ SCK3_MARK, SCK2_MARK, SCK1_MARK, SCK0_MARK,
+ IRL3_MARK, IRL2_MARK, IRL1_MARK, IRL0_MARK,
+ TXD3_MARK, TXD2_MARK, TXD1_MARK, TXD0_MARK,
+ RXD3_MARK, RXD2_MARK, RXD1_MARK, RXD0_MARK,
+
+ CE2B_MARK, CE2A_MARK, IOIS16_MARK,
+ STATUS1_MARK, STATUS0_MARK,
+
+ IRQOUT_MARK,
+
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t shx3_pinmux_data[] = {
+
+ /* PA GPIO */
+ PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
+ PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
+ PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
+ PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
+ PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
+ PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
+ PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
+ PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+
+ /* PB GPIO */
+ PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
+ PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
+ PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
+ PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
+ PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
+ PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
+ PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
+ PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+
+ /* PC GPIO */
+ PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
+ PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
+ PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
+ PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
+ PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
+ PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
+ PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
+ PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+
+ /* PD GPIO */
+ PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
+ PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
+ PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
+ PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
+ PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
+ PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
+ PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
+ PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+
+ /* PE GPIO */
+ PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
+ PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
+ PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT, PE5_IN_PU),
+ PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT, PE4_IN_PU),
+ PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT, PE3_IN_PU),
+ PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT, PE2_IN_PU),
+ PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT, PE1_IN_PU),
+ PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT, PE0_IN_PU),
+
+ /* PF GPIO */
+ PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
+ PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
+ PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
+ PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
+ PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
+ PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
+ PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
+ PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+
+ /* PG GPIO */
+ PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
+ PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
+ PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
+ PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT, PG4_IN_PU),
+ PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT, PG3_IN_PU),
+ PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT, PG2_IN_PU),
+ PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT, PG1_IN_PU),
+ PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT, PG0_IN_PU),
+
+ /* PH GPIO */
+ PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
+ PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
+ PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
+ PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
+ PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
+ PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+
+ /* PA FN */
+ PINMUX_DATA(D31_MARK, PA7_FN),
+ PINMUX_DATA(D30_MARK, PA6_FN),
+ PINMUX_DATA(D29_MARK, PA5_FN),
+ PINMUX_DATA(D28_MARK, PA4_FN),
+ PINMUX_DATA(D27_MARK, PA3_FN),
+ PINMUX_DATA(D26_MARK, PA2_FN),
+ PINMUX_DATA(D25_MARK, PA1_FN),
+ PINMUX_DATA(D24_MARK, PA0_FN),
+
+ /* PB FN */
+ PINMUX_DATA(D23_MARK, PB7_FN),
+ PINMUX_DATA(D22_MARK, PB6_FN),
+ PINMUX_DATA(D21_MARK, PB5_FN),
+ PINMUX_DATA(D20_MARK, PB4_FN),
+ PINMUX_DATA(D19_MARK, PB3_FN),
+ PINMUX_DATA(D18_MARK, PB2_FN),
+ PINMUX_DATA(D17_MARK, PB1_FN),
+ PINMUX_DATA(D16_MARK, PB0_FN),
+
+ /* PC FN */
+ PINMUX_DATA(BACK_MARK, PC7_FN),
+ PINMUX_DATA(BREQ_MARK, PC6_FN),
+ PINMUX_DATA(WE3_MARK, PC5_FN),
+ PINMUX_DATA(WE2_MARK, PC4_FN),
+ PINMUX_DATA(CS6_MARK, PC3_FN),
+ PINMUX_DATA(CS5_MARK, PC2_FN),
+ PINMUX_DATA(CS4_MARK, PC1_FN),
+ PINMUX_DATA(CLKOUTENB_MARK, PC0_FN),
+
+ /* PD FN */
+ PINMUX_DATA(DACK3_MARK, PD7_FN),
+ PINMUX_DATA(DACK2_MARK, PD6_FN),
+ PINMUX_DATA(DACK1_MARK, PD5_FN),
+ PINMUX_DATA(DACK0_MARK, PD4_FN),
+ PINMUX_DATA(DREQ3_MARK, PD3_FN),
+ PINMUX_DATA(DREQ2_MARK, PD2_FN),
+ PINMUX_DATA(DREQ1_MARK, PD1_FN),
+ PINMUX_DATA(DREQ0_MARK, PD0_FN),
+
+ /* PE FN */
+ PINMUX_DATA(IRQ3_MARK, PE7_FN),
+ PINMUX_DATA(IRQ2_MARK, PE6_FN),
+ PINMUX_DATA(IRQ1_MARK, PE5_FN),
+ PINMUX_DATA(IRQ0_MARK, PE4_FN),
+ PINMUX_DATA(DRAK3_MARK, PE3_FN),
+ PINMUX_DATA(DRAK2_MARK, PE2_FN),
+ PINMUX_DATA(DRAK1_MARK, PE1_FN),
+ PINMUX_DATA(DRAK0_MARK, PE0_FN),
+
+ /* PF FN */
+ PINMUX_DATA(SCK3_MARK, PF7_FN),
+ PINMUX_DATA(SCK2_MARK, PF6_FN),
+ PINMUX_DATA(SCK1_MARK, PF5_FN),
+ PINMUX_DATA(SCK0_MARK, PF4_FN),
+ PINMUX_DATA(IRL3_MARK, PF3_FN),
+ PINMUX_DATA(IRL2_MARK, PF2_FN),
+ PINMUX_DATA(IRL1_MARK, PF1_FN),
+ PINMUX_DATA(IRL0_MARK, PF0_FN),
+
+ /* PG FN */
+ PINMUX_DATA(TXD3_MARK, PG7_FN),
+ PINMUX_DATA(TXD2_MARK, PG6_FN),
+ PINMUX_DATA(TXD1_MARK, PG5_FN),
+ PINMUX_DATA(TXD0_MARK, PG4_FN),
+ PINMUX_DATA(RXD3_MARK, PG3_FN),
+ PINMUX_DATA(RXD2_MARK, PG2_FN),
+ PINMUX_DATA(RXD1_MARK, PG1_FN),
+ PINMUX_DATA(RXD0_MARK, PG0_FN),
+
+ /* PH FN */
+ PINMUX_DATA(CE2B_MARK, PH5_FN),
+ PINMUX_DATA(CE2A_MARK, PH4_FN),
+ PINMUX_DATA(IOIS16_MARK, PH3_FN),
+ PINMUX_DATA(STATUS1_MARK, PH2_FN),
+ PINMUX_DATA(STATUS0_MARK, PH1_FN),
+ PINMUX_DATA(IRQOUT_MARK, PH0_FN),
+};
+
+static struct pinmux_gpio shx3_pinmux_gpios[] = {
+ /* PA */
+ PINMUX_GPIO(GPIO_PA7, PA7_DATA),
+ PINMUX_GPIO(GPIO_PA6, PA6_DATA),
+ PINMUX_GPIO(GPIO_PA5, PA5_DATA),
+ PINMUX_GPIO(GPIO_PA4, PA4_DATA),
+ PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+ PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+ PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+ PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+ /* PB */
+ PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+ PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+ PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+ PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+ PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+ PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+ PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+ PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+
+ /* PC */
+ PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+ PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+ PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+ PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+ PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+ PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+ PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+ PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+ /* PD */
+ PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+ PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+ PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+ PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+ PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+ PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+ PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+ PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+ /* PE */
+ PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+ PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+ PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+ PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+ PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+ PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+ PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+ PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+ /* PF */
+ PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+ PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+ PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+ PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+ PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+ PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+ PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+ PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+ /* PG */
+ PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+ PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+ PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+ PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+ PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+ PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+ PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+ PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+ /* PH */
+ PINMUX_GPIO(GPIO_PH5, PH5_DATA),
+ PINMUX_GPIO(GPIO_PH4, PH4_DATA),
+ PINMUX_GPIO(GPIO_PH3, PH3_DATA),
+ PINMUX_GPIO(GPIO_PH2, PH2_DATA),
+ PINMUX_GPIO(GPIO_PH1, PH1_DATA),
+ PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+
+ /* FN */
+ PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
+ PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
+ PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
+ PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
+ PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
+ PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
+ PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
+ PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
+ PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
+ PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
+ PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
+ PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
+ PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
+ PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
+ PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
+ PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
+ PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+ PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_WE3, WE3_MARK),
+ PINMUX_GPIO(GPIO_FN_WE2, WE2_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_CLKOUTENB, CLKOUTENB_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK3, DACK3_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK2, DACK2_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ3, DREQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ2, DREQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3, IRQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK3, DRAK3_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK2, DRAK2_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK1, DRAK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK0, DRAK0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL3, IRL3_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL2, IRL2_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL1, IRL1_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL0, IRL0_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQOUT, IRQOUT_MARK),
+};
+
+static struct pinmux_cfg_reg shx3_pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PABCR", 0xffc70000, 32, 2) {
+ PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
+ PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
+ PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
+ PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
+ PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
+ PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
+ PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
+ PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU,
+ PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
+ PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
+ PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
+ PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
+ PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
+ PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
+ PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
+ PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU, },
+ },
+ { PINMUX_CFG_REG("PCDCR", 0xffc70004, 32, 2) {
+ PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
+ PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
+ PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
+ PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
+ PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
+ PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
+ PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
+ PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU,
+ PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
+ PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
+ PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
+ PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
+ PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
+ PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
+ PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
+ PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU, },
+ },
+ { PINMUX_CFG_REG("PEFCR", 0xffc70008, 32, 2) {
+ PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
+ PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
+ PE5_FN, PE5_OUT, PE5_IN, PE5_IN_PU,
+ PE4_FN, PE4_OUT, PE4_IN, PE4_IN_PU,
+ PE3_FN, PE3_OUT, PE3_IN, PE3_IN_PU,
+ PE2_FN, PE2_OUT, PE2_IN, PE2_IN_PU,
+ PE1_FN, PE1_OUT, PE1_IN, PE1_IN_PU,
+ PE0_FN, PE0_OUT, PE0_IN, PE0_IN_PU,
+ PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
+ PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
+ PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
+ PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
+ PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
+ PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
+ PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
+ PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU, },
+ },
+ { PINMUX_CFG_REG("PGHCR", 0xffc7000c, 32, 2) {
+ PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
+ PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
+ PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
+ PG4_FN, PG4_OUT, PG4_IN, PG4_IN_PU,
+ PG3_FN, PG3_OUT, PG3_IN, PG3_IN_PU,
+ PG2_FN, PG2_OUT, PG2_IN, PG2_IN_PU,
+ PG1_FN, PG1_OUT, PG1_IN, PG1_IN_PU,
+ PG0_FN, PG0_OUT, PG0_IN, PG0_IN_PU,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
+ PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
+ PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
+ PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
+ PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
+ PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU, },
+ },
+ { },
+};
+
+static struct pinmux_data_reg shx3_pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PABDR", 0xffc70010, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA, },
+ },
+ { PINMUX_DATA_REG("PCDDR", 0xffc70014, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA, },
+ },
+ { PINMUX_DATA_REG("PEFDR", 0xffc70018, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA, },
+ },
+ { PINMUX_DATA_REG("PGHDR", 0xffc7001c, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA, },
+ },
+ { },
+};
+
+static struct pinmux_info shx3_pinmux_info = {
+ .name = "shx3_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .input_pu = { PINMUX_INPUT_PULLUP_BEGIN,
+ PINMUX_INPUT_PULLUP_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+ .first_gpio = GPIO_PA7,
+ .last_gpio = GPIO_FN_IRQOUT,
+ .gpios = shx3_pinmux_gpios,
+ .gpio_data = shx3_pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(shx3_pinmux_data),
+ .cfg_regs = shx3_pinmux_config_regs,
+ .data_regs = shx3_pinmux_data_regs,
+};
+
+static int __init shx3_pinmux_setup(void)
+{
+ return register_pinmux(&shx3_pinmux_info);
+}
+arch_initcall(shx3_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
index 79c556e56262..828c9657eb52 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
@@ -524,6 +524,70 @@ static struct platform_device veu1_device = {
},
};
+/* BEU0 */
+static struct uio_info beu0_platform_data = {
+ .name = "BEU0",
+ .version = "0",
+ .irq = evt2irq(0x8A0),
+};
+
+static struct resource beu0_resources[] = {
+ [0] = {
+ .name = "BEU0",
+ .start = 0xfe930000,
+ .end = 0xfe933400,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* place holder for contiguous memory */
+ },
+};
+
+static struct platform_device beu0_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 6,
+ .dev = {
+ .platform_data = &beu0_platform_data,
+ },
+ .resource = beu0_resources,
+ .num_resources = ARRAY_SIZE(beu0_resources),
+ .archdata = {
+ .hwblk_id = HWBLK_BEU0,
+ },
+};
+
+/* BEU1 */
+static struct uio_info beu1_platform_data = {
+ .name = "BEU1",
+ .version = "0",
+ .irq = evt2irq(0xA00),
+};
+
+static struct resource beu1_resources[] = {
+ [0] = {
+ .name = "BEU1",
+ .start = 0xfe940000,
+ .end = 0xfe943400,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* place holder for contiguous memory */
+ },
+};
+
+static struct platform_device beu1_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 7,
+ .dev = {
+ .platform_data = &beu1_platform_data,
+ },
+ .resource = beu1_resources,
+ .num_resources = ARRAY_SIZE(beu1_resources),
+ .archdata = {
+ .hwblk_id = HWBLK_BEU1,
+ },
+};
+
static struct sh_timer_config cmt_platform_data = {
.channel_offset = 0x60,
.timer_bit = 5,
@@ -857,6 +921,8 @@ static struct platform_device *sh7724_devices[] __initdata = {
&vpu_device,
&veu0_device,
&veu1_device,
+ &beu0_device,
+ &beu1_device,
&jpu_device,
&spu0_device,
&spu1_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
index 444aca95b20d..749c6388d5a5 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
@@ -26,7 +26,7 @@ static struct plat_sci_port scif2_platform_data = {
static struct platform_device scif2_device = {
.name = "sh-sci",
- .id = 2,
+ .id = 0,
.dev = {
.platform_data = &scif2_platform_data,
},
@@ -41,7 +41,7 @@ static struct plat_sci_port scif3_platform_data = {
static struct platform_device scif3_device = {
.name = "sh-sci",
- .id = 3,
+ .id = 1,
.dev = {
.platform_data = &scif3_platform_data,
},
@@ -56,7 +56,7 @@ static struct plat_sci_port scif4_platform_data = {
static struct platform_device scif4_device = {
.name = "sh-sci",
- .id = 4,
+ .id = 2,
.dev = {
.platform_data = &scif4_platform_data,
},
@@ -163,39 +163,23 @@ enum {
IRL4_HHLL, IRL4_HHLH, IRL4_HHHL,
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
- SDHI,
- DVC,
- IRQ8, IRQ9, IRQ10,
- WDT0,
- TMU0, TMU1, TMU2, TMU2_TICPI,
+ SDHI, DVC,
+ IRQ8, IRQ9, IRQ11, IRQ10, IRQ12, IRQ13, IRQ14, IRQ15,
+ TMU0, TMU1, TMU2, TMU2_TICPI, TMU3, TMU4, TMU5,
HUDI,
-
ARC4,
- DMAC0,
- IRQ11,
- SCIF2,
- DMAC1_6,
- USB0,
- IRQ12,
+ DMAC0_5, DMAC6_7, DMAC8_11,
+ SCIF0, SCIF1, SCIF2, SCIF3, SCIF4,
+ USB0, USB1,
JMC,
- SPI1,
- IRQ13, IRQ14,
- USB1,
+ SPI0, SPI1,
TMR01, TMR23, TMR45,
- WDT1,
FRT,
- LPC,
- SCIF0, SCIF1, SCIF3,
- PECI0I, PECI1I, PECI2I,
- IRQ15,
+ LPC, LPC5, LPC6, LPC7, LPC8,
+ PECI0, PECI1, PECI2, PECI3, PECI4, PECI5,
ETHERC,
- SPI0,
- ADC1,
- DMAC1_8,
+ ADC0, ADC1,
SIM,
- TMU3, TMU4, TMU5,
- ADC0,
- SCIF4,
IIC0_0, IIC0_1, IIC0_2, IIC0_3,
IIC1_0, IIC1_1, IIC1_2, IIC1_3,
IIC2_0, IIC2_1, IIC2_2, IIC2_3,
@@ -206,9 +190,23 @@ enum {
IIC7_0, IIC7_1, IIC7_2, IIC7_3,
IIC8_0, IIC8_1, IIC8_2, IIC8_3,
IIC9_0, IIC9_1, IIC9_2, IIC9_3,
- PCIINTA,
- PCIE,
+ ONFICTL,
+ MMC1, MMC2,
+ ECCU,
+ PCIC,
+ G200,
+ RSPI,
SGPIO,
+ DMINT12, DMINT13, DMINT14, DMINT15, DMINT16, DMINT17, DMINT18, DMINT19,
+ DMINT20, DMINT21, DMINT22, DMINT23,
+ DDRECC,
+ TSIP,
+ PCIE_BRIDGE,
+ WDT0B, WDT1B, WDT2B, WDT3B, WDT4B, WDT5B, WDT6B, WDT7B, WDT8B,
+ GETHER0, GETHER1, GETHER2,
+ PBIA, PBIB, PBIC,
+ DMAE2, DMAE3,
+ SERMUX2, SERMUX3,
/* interrupt groups */
@@ -221,19 +219,18 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(DVC, 0x4e0),
INTC_VECT(IRQ8, 0x500), INTC_VECT(IRQ9, 0x520),
INTC_VECT(IRQ10, 0x540),
- INTC_VECT(WDT0, 0x560),
INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
INTC_VECT(HUDI, 0x600),
INTC_VECT(ARC4, 0x620),
- INTC_VECT(DMAC0, 0x640), INTC_VECT(DMAC0, 0x660),
- INTC_VECT(DMAC0, 0x680), INTC_VECT(DMAC0, 0x6a0),
- INTC_VECT(DMAC0, 0x6c0),
+ INTC_VECT(DMAC0_5, 0x640), INTC_VECT(DMAC0_5, 0x660),
+ INTC_VECT(DMAC0_5, 0x680), INTC_VECT(DMAC0_5, 0x6a0),
+ INTC_VECT(DMAC0_5, 0x6c0),
INTC_VECT(IRQ11, 0x6e0),
INTC_VECT(SCIF2, 0x700), INTC_VECT(SCIF2, 0x720),
INTC_VECT(SCIF2, 0x740), INTC_VECT(SCIF2, 0x760),
- INTC_VECT(DMAC0, 0x780), INTC_VECT(DMAC0, 0x7a0),
- INTC_VECT(DMAC1_6, 0x7c0), INTC_VECT(DMAC1_6, 0x7e0),
+ INTC_VECT(DMAC0_5, 0x780), INTC_VECT(DMAC0_5, 0x7a0),
+ INTC_VECT(DMAC6_7, 0x7c0), INTC_VECT(DMAC6_7, 0x7e0),
INTC_VECT(USB0, 0x840),
INTC_VECT(IRQ12, 0x880),
INTC_VECT(JMC, 0x8a0),
@@ -242,7 +239,6 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(USB1, 0x920),
INTC_VECT(TMR01, 0xa00), INTC_VECT(TMR23, 0xa20),
INTC_VECT(TMR45, 0xa40),
- INTC_VECT(WDT1, 0xa60),
INTC_VECT(FRT, 0xa80),
INTC_VECT(LPC, 0xaa0), INTC_VECT(LPC, 0xac0),
INTC_VECT(LPC, 0xae0), INTC_VECT(LPC, 0xb00),
@@ -250,14 +246,14 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(SCIF0, 0xb40), INTC_VECT(SCIF1, 0xb60),
INTC_VECT(SCIF3, 0xb80), INTC_VECT(SCIF3, 0xba0),
INTC_VECT(SCIF3, 0xbc0), INTC_VECT(SCIF3, 0xbe0),
- INTC_VECT(PECI0I, 0xc00), INTC_VECT(PECI1I, 0xc20),
- INTC_VECT(PECI2I, 0xc40),
+ INTC_VECT(PECI0, 0xc00), INTC_VECT(PECI1, 0xc20),
+ INTC_VECT(PECI2, 0xc40),
INTC_VECT(IRQ15, 0xc60),
INTC_VECT(ETHERC, 0xc80), INTC_VECT(ETHERC, 0xca0),
INTC_VECT(SPI0, 0xcc0),
INTC_VECT(ADC1, 0xce0),
- INTC_VECT(DMAC1_8, 0xd00), INTC_VECT(DMAC1_8, 0xd20),
- INTC_VECT(DMAC1_8, 0xd40), INTC_VECT(DMAC1_8, 0xd60),
+ INTC_VECT(DMAC8_11, 0xd00), INTC_VECT(DMAC8_11, 0xd20),
+ INTC_VECT(DMAC8_11, 0xd40), INTC_VECT(DMAC8_11, 0xd60),
INTC_VECT(SIM, 0xd80), INTC_VECT(SIM, 0xda0),
INTC_VECT(SIM, 0xdc0), INTC_VECT(SIM, 0xde0),
INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
@@ -278,17 +274,47 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(IIC5_0, 0x1860), INTC_VECT(IIC5_1, 0x1880),
INTC_VECT(IIC5_2, 0x18a0), INTC_VECT(IIC5_3, 0x18c0),
INTC_VECT(IIC6_0, 0x18e0), INTC_VECT(IIC6_1, 0x1900),
- INTC_VECT(IIC6_2, 0x1920), INTC_VECT(IIC6_3, 0x1980),
+ INTC_VECT(IIC6_2, 0x1920),
+ INTC_VECT(ONFICTL, 0x1960),
+ INTC_VECT(IIC6_3, 0x1980),
INTC_VECT(IIC7_0, 0x19a0), INTC_VECT(IIC7_1, 0x1a00),
INTC_VECT(IIC7_2, 0x1a20), INTC_VECT(IIC7_3, 0x1a40),
INTC_VECT(IIC8_0, 0x1a60), INTC_VECT(IIC8_1, 0x1a80),
INTC_VECT(IIC8_2, 0x1aa0), INTC_VECT(IIC8_3, 0x1b40),
INTC_VECT(IIC9_0, 0x1b60), INTC_VECT(IIC9_1, 0x1b80),
INTC_VECT(IIC9_2, 0x1c00), INTC_VECT(IIC9_3, 0x1c20),
- INTC_VECT(PCIINTA, 0x1ce0),
- INTC_VECT(PCIE, 0x1e00),
- INTC_VECT(SGPIO, 0x1f80),
- INTC_VECT(SGPIO, 0x1fa0),
+ INTC_VECT(MMC1, 0x1c60), INTC_VECT(MMC2, 0x1c80),
+ INTC_VECT(ECCU, 0x1cc0),
+ INTC_VECT(PCIC, 0x1ce0),
+ INTC_VECT(G200, 0x1d00),
+ INTC_VECT(RSPI, 0x1d80), INTC_VECT(RSPI, 0x1da0),
+ INTC_VECT(RSPI, 0x1dc0), INTC_VECT(RSPI, 0x1de0),
+ INTC_VECT(PECI3, 0x1ec0), INTC_VECT(PECI4, 0x1ee0),
+ INTC_VECT(PECI5, 0x1f00),
+ INTC_VECT(SGPIO, 0x1f80), INTC_VECT(SGPIO, 0x1fa0),
+ INTC_VECT(SGPIO, 0x1fc0),
+ INTC_VECT(DMINT12, 0x2400), INTC_VECT(DMINT13, 0x2420),
+ INTC_VECT(DMINT14, 0x2440), INTC_VECT(DMINT15, 0x2460),
+ INTC_VECT(DMINT16, 0x2480), INTC_VECT(DMINT17, 0x24e0),
+ INTC_VECT(DMINT18, 0x2500), INTC_VECT(DMINT19, 0x2520),
+ INTC_VECT(DMINT20, 0x2540), INTC_VECT(DMINT21, 0x2560),
+ INTC_VECT(DMINT22, 0x2580), INTC_VECT(DMINT23, 0x2600),
+ INTC_VECT(DDRECC, 0x2620),
+ INTC_VECT(TSIP, 0x2640),
+ INTC_VECT(PCIE_BRIDGE, 0x27c0),
+ INTC_VECT(WDT0B, 0x2800), INTC_VECT(WDT1B, 0x2820),
+ INTC_VECT(WDT2B, 0x2840), INTC_VECT(WDT3B, 0x2860),
+ INTC_VECT(WDT4B, 0x2880), INTC_VECT(WDT5B, 0x28a0),
+ INTC_VECT(WDT6B, 0x28c0), INTC_VECT(WDT7B, 0x28e0),
+ INTC_VECT(WDT8B, 0x2900),
+ INTC_VECT(GETHER0, 0x2960), INTC_VECT(GETHER1, 0x2980),
+ INTC_VECT(GETHER2, 0x29a0),
+ INTC_VECT(PBIA, 0x2a00), INTC_VECT(PBIB, 0x2a20),
+ INTC_VECT(PBIC, 0x2a40),
+ INTC_VECT(DMAE2, 0x2a60), INTC_VECT(DMAE3, 0x2a80),
+ INTC_VECT(SERMUX2, 0x2aa0), INTC_VECT(SERMUX3, 0x2b40),
+ INTC_VECT(LPC5, 0x2b60), INTC_VECT(LPC6, 0x2b80),
+ INTC_VECT(LPC7, 0x2c00), INTC_VECT(LPC8, 0x2c20),
};
static struct intc_group groups[] __initdata = {
@@ -312,31 +338,45 @@ static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
{ 0, 0, 0, 0, 0, 0, 0, 0,
- 0, DMAC1_8, 0, PECI0I, LPC, FRT, WDT1, TMR45,
- TMR23, TMR01, 0, 0, 0, 0, 0, DMAC0,
- HUDI, 0, WDT0, SCIF3, SCIF2, SDHI, TMU345, TMU012
+ 0, DMAC8_11, 0, PECI0, LPC, FRT, 0, TMR45,
+ TMR23, TMR01, 0, 0, 0, 0, 0, DMAC0_5,
+ HUDI, 0, 0, SCIF3, SCIF2, SDHI, TMU345, TMU012
} },
{ 0xffd400d0, 0xffd400d4, 32, /* INT2MSKR1 / INT2MSKCR1 */
{ IRQ15, IRQ14, IRQ13, IRQ12, IRQ11, IRQ10, SCIF4, ETHERC,
IRQ9, IRQ8, SCIF1, SCIF0, USB0, 0, 0, USB1,
- ADC1, 0, DMAC1_6, ADC0, SPI0, SIM, PECI2I, PECI1I,
+ ADC1, 0, DMAC6_7, ADC0, SPI0, SIM, PECI2, PECI1,
ARC4, 0, SPI1, JMC, 0, 0, 0, DVC
} },
{ 0xffd10038, 0xffd1003c, 32, /* INT2MSKR2 / INT2MSKCR2 */
- { IIC4_1, IIC4_2, IIC5_0, 0, 0, 0, SGPIO, 0,
- 0, 0, 0, IIC9_2, IIC8_2, IIC8_1, IIC8_0, IIC7_3,
+ { IIC4_1, IIC4_2, IIC5_0, ONFICTL, 0, 0, SGPIO, 0,
+ 0, G200, 0, IIC9_2, IIC8_2, IIC8_1, IIC8_0, IIC7_3,
IIC7_2, IIC7_1, IIC6_3, IIC0_0, IIC0_1, IIC0_2, IIC0_3, IIC3_1,
- IIC2_3, 0, IIC2_1, IIC9_1, IIC3_3, IIC1_0, PCIE, IIC2_2
+ IIC2_3, 0, IIC2_1, IIC9_1, IIC3_3, IIC1_0, 0, IIC2_2
} },
- { 0xffd100d0, 0xff1400d4, 32, /* INT2MSKR3 / INT2MSKCR4 */
- { 0, IIC6_1, IIC6_0, IIC5_1, IIC3_2, IIC2_0, 0, 0,
+ { 0xffd100d0, 0xffd100d4, 32, /* INT2MSKR3 / INT2MSKCR3 */
+ { MMC1, IIC6_1, IIC6_0, IIC5_1, IIC3_2, IIC2_0, PECI5, MMC2,
IIC1_3, IIC1_2, IIC9_0, IIC8_3, IIC4_3, IIC7_0, 0, IIC6_2,
- PCIINTA, 0, IIC4_0, 0, 0, 0, 0, IIC9_3,
+ PCIC, 0, IIC4_0, 0, ECCU, RSPI, 0, IIC9_3,
IIC3_0, 0, IIC5_3, IIC5_2, 0, 0, 0, IIC1_1
} },
+
+ { 0xffd20038, 0xffd2003c, 32, /* INT2MSKR4 / INT2MSKCR4 */
+ { WDT0B, WDT1B, WDT3B, GETHER0, 0, 0, 0, 0,
+ 0, 0, 0, LPC7, SERMUX2, DMAE3, DMAE2, PBIC,
+ PBIB, PBIA, GETHER1, DMINT12, DMINT13, DMINT14, DMINT15, TSIP,
+ DMINT23, 0, DMINT21, LPC6, 0, DMINT16, 0, DMINT22
+ } },
+
+ { 0xffd200d0, 0xffd200d4, 32, /* INT2MSKR5 / INT2MSKCR5 */
+ { 0, WDT8B, WDT7B, WDT4B, 0, DMINT20, 0, 0,
+ DMINT19, DMINT18, LPC5, SERMUX3, WDT2B, GETHER2, 0, 0,
+ 0, 0, PCIE_BRIDGE, 0, 0, 0, 0, LPC8,
+ DDRECC, 0, WDT6B, WDT5B, 0, 0, 0, DMINT17
+ } },
};
#define INTPRI 0xffd00010
@@ -372,6 +412,22 @@ static struct intc_mask_reg mask_registers[] __initdata = {
#define INT2PRI29 0xffd100b4
#define INT2PRI30 0xffd100b8
#define INT2PRI31 0xffd100bc
+#define INT2PRI32 0xffd20000
+#define INT2PRI33 0xffd20004
+#define INT2PRI34 0xffd20008
+#define INT2PRI35 0xffd2000c
+#define INT2PRI36 0xffd20010
+#define INT2PRI37 0xffd20014
+#define INT2PRI38 0xffd20018
+#define INT2PRI39 0xffd2001c
+#define INT2PRI40 0xffd200a0
+#define INT2PRI41 0xffd200a4
+#define INT2PRI42 0xffd200a8
+#define INT2PRI43 0xffd200ac
+#define INT2PRI44 0xffd200b0
+#define INT2PRI45 0xffd200b4
+#define INT2PRI46 0xffd200b8
+#define INT2PRI47 0xffd200bc
static struct intc_prio_reg prio_registers[] __initdata = {
{ INTPRI, 0, 32, 4, { IRQ0, IRQ1, IRQ2, IRQ3,
@@ -379,39 +435,61 @@ static struct intc_prio_reg prio_registers[] __initdata = {
{ INT2PRI0, 0, 32, 8, { TMU0, TMU1, TMU2, TMU2_TICPI } },
{ INT2PRI1, 0, 32, 8, { TMU3, TMU4, TMU5, SDHI } },
- { INT2PRI2, 0, 32, 8, { SCIF2, SCIF3, WDT0, IRQ8 } },
- { INT2PRI3, 0, 32, 8, { HUDI, DMAC0, ADC0, IRQ9 } },
+ { INT2PRI2, 0, 32, 8, { SCIF2, SCIF3, 0, IRQ8 } },
+ { INT2PRI3, 0, 32, 8, { HUDI, DMAC0_5, ADC0, IRQ9 } },
{ INT2PRI4, 0, 32, 8, { IRQ10, 0, TMR01, TMR23 } },
- { INT2PRI5, 0, 32, 8, { TMR45, WDT1, FRT, LPC } },
- { INT2PRI6, 0, 32, 8, { PECI0I, ETHERC, DMAC1_8, 0 } },
+ { INT2PRI5, 0, 32, 8, { TMR45, 0, FRT, LPC } },
+ { INT2PRI6, 0, 32, 8, { PECI0, ETHERC, DMAC8_11, 0 } },
{ INT2PRI7, 0, 32, 8, { SCIF4, 0, IRQ11, IRQ12 } },
{ INT2PRI8, 0, 32, 8, { 0, 0, 0, DVC } },
{ INT2PRI9, 0, 32, 8, { ARC4, 0, SPI1, JMC } },
- { INT2PRI10, 0, 32, 8, { SPI0, SIM, PECI2I, PECI1I } },
- { INT2PRI11, 0, 32, 8, { ADC1, IRQ13, DMAC1_6, IRQ14 } },
+ { INT2PRI10, 0, 32, 8, { SPI0, SIM, PECI2, PECI1 } },
+ { INT2PRI11, 0, 32, 8, { ADC1, IRQ13, DMAC6_7, IRQ14 } },
{ INT2PRI12, 0, 32, 8, { USB0, 0, IRQ15, USB1 } },
{ INT2PRI13, 0, 32, 8, { 0, 0, SCIF1, SCIF0 } },
{ INT2PRI16, 0, 32, 8, { IIC2_2, 0, 0, 0 } },
- { INT2PRI17, 0, 32, 8, { PCIE, 0, 0, IIC1_0 } },
+ { INT2PRI17, 0, 32, 8, { 0, 0, 0, IIC1_0 } },
{ INT2PRI18, 0, 32, 8, { IIC3_3, IIC9_1, IIC2_1, IIC1_2 } },
{ INT2PRI19, 0, 32, 8, { IIC2_3, IIC3_1, 0, IIC1_3 } },
{ INT2PRI20, 0, 32, 8, { IIC2_0, IIC6_3, IIC7_1, IIC7_2 } },
{ INT2PRI21, 0, 32, 8, { IIC7_3, IIC8_0, IIC8_1, IIC8_2 } },
- { INT2PRI22, 0, 32, 8, { IIC9_2, 0, 0, 0 } },
- { INT2PRI23, 0, 32, 8, { 0, SGPIO, IIC3_2, IIC5_1 } },
- { INT2PRI24, 0, 32, 8, { 0, 0, 0, IIC1_1 } },
+ { INT2PRI22, 0, 32, 8, { IIC9_2, MMC2, G200, 0 } },
+ { INT2PRI23, 0, 32, 8, { PECI5, SGPIO, IIC3_2, IIC5_1 } },
+ { INT2PRI24, 0, 32, 8, { PECI4, PECI3, 0, IIC1_1 } },
{ INT2PRI25, 0, 32, 8, { IIC3_0, 0, IIC5_3, IIC5_2 } },
- { INT2PRI26, 0, 32, 8, { 0, 0, 0, IIC9_3 } },
- { INT2PRI27, 0, 32, 8, { PCIINTA, IIC6_0, IIC4_0, IIC6_1 } },
- { INT2PRI28, 0, 32, 8, { IIC4_3, IIC7_0, 0, IIC6_2 } },
+ { INT2PRI26, 0, 32, 8, { ECCU, RSPI, 0, IIC9_3 } },
+ { INT2PRI27, 0, 32, 8, { PCIC, IIC6_0, IIC4_0, IIC6_1 } },
+ { INT2PRI28, 0, 32, 8, { IIC4_3, IIC7_0, MMC1, IIC6_2 } },
{ INT2PRI29, 0, 32, 8, { 0, 0, IIC9_0, IIC8_3 } },
- { INT2PRI30, 0, 32, 8, { IIC4_1, IIC4_2, IIC5_0, 0 } },
+ { INT2PRI30, 0, 32, 8, { IIC4_1, IIC4_2, IIC5_0, ONFICTL } },
{ INT2PRI31, 0, 32, 8, { IIC0_0, IIC0_1, IIC0_2, IIC0_3 } },
+ { INT2PRI32, 0, 32, 8, { DMINT22, 0, 0, 0 } },
+ { INT2PRI33, 0, 32, 8, { 0, 0, 0, DMINT16 } },
+ { INT2PRI34, 0, 32, 8, { 0, LPC6, DMINT21, DMINT18 } },
+ { INT2PRI35, 0, 32, 8, { DMINT23, TSIP, 0, DMINT19 } },
+ { INT2PRI36, 0, 32, 8, { DMINT20, GETHER1, PBIA, PBIB } },
+ { INT2PRI37, 0, 32, 8, { PBIC, DMAE2, DMAE3, SERMUX2 } },
+ { INT2PRI38, 0, 32, 8, { LPC7, 0, 0, 0 } },
+ { INT2PRI39, 0, 32, 8, { 0, 0, 0, WDT4B } },
+ { INT2PRI40, 0, 32, 8, { 0, 0, 0, DMINT17 } },
+ { INT2PRI41, 0, 32, 8, { DDRECC, 0, WDT6B, WDT5B } },
+ { INT2PRI42, 0, 32, 8, { 0, 0, 0, LPC8 } },
+ { INT2PRI43, 0, 32, 8, { 0, WDT7B, PCIE_BRIDGE, WDT8B } },
+ { INT2PRI44, 0, 32, 8, { WDT2B, GETHER2, 0, 0 } },
+ { INT2PRI45, 0, 32, 8, { 0, 0, LPC5, SERMUX3 } },
+ { INT2PRI46, 0, 32, 8, { WDT0B, WDT1B, WDT3B, GETHER0 } },
+ { INT2PRI47, 0, 32, 8, { DMINT12, DMINT13, DMINT14, DMINT15 } },
+};
+
+static struct intc_sense_reg sense_registers_irq8to15[] __initdata = {
+ { 0xffd100f8, 32, 2, /* ICR2 */ { IRQ15, IRQ14, IRQ13, IRQ12,
+ IRQ11, IRQ10, IRQ9, IRQ8 } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7757", vectors, groups,
- mask_registers, prio_registers, NULL);
+ mask_registers, prio_registers,
+ sense_registers_irq8to15);
/* Support for external interrupt pins in IRQ mode */
static struct intc_vect vectors_irq0123[] __initdata = {
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
index 8797723231ea..c016c0004714 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
@@ -629,33 +629,10 @@ static void __init sh7786_usb_setup(void)
}
}
-static int __init sh7786_devices_setup(void)
-{
- int ret;
-
- sh7786_usb_setup();
-
- ret = platform_add_devices(sh7786_early_devices,
- ARRAY_SIZE(sh7786_early_devices));
- if (unlikely(ret != 0))
- return ret;
-
- return platform_add_devices(sh7786_devices,
- ARRAY_SIZE(sh7786_devices));
-}
-arch_initcall(sh7786_devices_setup);
-
-void __init plat_early_device_setup(void)
-{
- early_platform_add_devices(sh7786_early_devices,
- ARRAY_SIZE(sh7786_early_devices));
-}
-
enum {
UNUSED = 0,
/* interrupt sources */
-
IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
@@ -693,9 +670,12 @@ enum {
Thermal,
INTICI0, INTICI1, INTICI2, INTICI3,
INTICI4, INTICI5, INTICI6, INTICI7,
+
+ /* Muxed sub-events */
+ TXI1, BRI1, RXI1, ERI1,
};
-static struct intc_vect vectors[] __initdata = {
+static struct intc_vect sh7786_vectors[] __initdata = {
INTC_VECT(WDT, 0x3e0),
INTC_VECT(TMU0_0, 0x400), INTC_VECT(TMU0_1, 0x420),
INTC_VECT(TMU0_2, 0x440), INTC_VECT(TMU0_3, 0x460),
@@ -756,14 +736,12 @@ static struct intc_vect vectors[] __initdata = {
#define INTDISTCR0 0xfe4100b0
#define INTDISTCR1 0xfe4100b4
-#define INTACK 0xfe4100b8
-#define INTACKCLR 0xfe4100bc
#define INT2DISTCR0 0xfe410900
#define INT2DISTCR1 0xfe410904
#define INT2DISTCR2 0xfe410908
#define INT2DISTCR3 0xfe41090c
-static struct intc_mask_reg mask_registers[] __initdata = {
+static struct intc_mask_reg sh7786_mask_registers[] __initdata = {
{ CnINTMSK0, CnINTMSKCLR0, 32,
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 },
INTC_SMP_BALANCING(INTDISTCR0) },
@@ -807,7 +785,7 @@ static struct intc_mask_reg mask_registers[] __initdata = {
0, 0, 0, 0, 0, 0, 0, 0 }, INTC_SMP_BALANCING(INT2DISTCR3) },
};
-static struct intc_prio_reg prio_registers[] __initdata = {
+static struct intc_prio_reg sh7786_prio_registers[] __initdata = {
{ 0xfe410010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
IRQ4, IRQ5, IRQ6, IRQ7 } },
{ 0xfe410800, 0, 32, 8, /* INT2PRI0 */ { 0, 0, 0, WDT } },
@@ -851,11 +829,27 @@ static struct intc_prio_reg prio_registers[] __initdata = {
INTICI3, INTICI2, INTICI1, INTICI0 }, INTC_SMP(4, 2) },
};
-static DECLARE_INTC_DESC(intc_desc, "sh7786", vectors, NULL,
- mask_registers, prio_registers, NULL);
+static struct intc_subgroup sh7786_subgroups[] __initdata = {
+ { 0xfe410c20, 32, SCIF1,
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TXI1, BRI1, RXI1, ERI1 } },
+};
-/* Support for external interrupt pins in IRQ mode */
+static struct intc_desc sh7786_intc_desc __initdata = {
+ .name = "sh7786",
+ .hw = {
+ .vectors = sh7786_vectors,
+ .nr_vectors = ARRAY_SIZE(sh7786_vectors),
+ .mask_regs = sh7786_mask_registers,
+ .nr_mask_regs = ARRAY_SIZE(sh7786_mask_registers),
+ .subgroups = sh7786_subgroups,
+ .nr_subgroups = ARRAY_SIZE(sh7786_subgroups),
+ .prio_regs = sh7786_prio_registers,
+ .nr_prio_regs = ARRAY_SIZE(sh7786_prio_registers),
+ },
+};
+/* Support for external interrupt pins in IRQ mode */
static struct intc_vect vectors_irq0123[] __initdata = {
INTC_VECT(IRQ0, 0x200), INTC_VECT(IRQ1, 0x240),
INTC_VECT(IRQ2, 0x280), INTC_VECT(IRQ3, 0x2c0),
@@ -866,23 +860,25 @@ static struct intc_vect vectors_irq4567[] __initdata = {
INTC_VECT(IRQ6, 0x380), INTC_VECT(IRQ7, 0x3c0),
};
-static struct intc_sense_reg sense_registers[] __initdata = {
+static struct intc_sense_reg sh7786_sense_registers[] __initdata = {
{ 0xfe41001c, 32, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3,
IRQ4, IRQ5, IRQ6, IRQ7 } },
};
-static struct intc_mask_reg ack_registers[] __initdata = {
+static struct intc_mask_reg sh7786_ack_registers[] __initdata = {
{ 0xfe410024, 0, 32, /* INTREQ */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static DECLARE_INTC_DESC_ACK(intc_desc_irq0123, "sh7786-irq0123",
- vectors_irq0123, NULL, mask_registers,
- prio_registers, sense_registers, ack_registers);
+ vectors_irq0123, NULL, sh7786_mask_registers,
+ sh7786_prio_registers, sh7786_sense_registers,
+ sh7786_ack_registers);
static DECLARE_INTC_DESC_ACK(intc_desc_irq4567, "sh7786-irq4567",
- vectors_irq4567, NULL, mask_registers,
- prio_registers, sense_registers, ack_registers);
+ vectors_irq4567, NULL, sh7786_mask_registers,
+ sh7786_prio_registers, sh7786_sense_registers,
+ sh7786_ack_registers);
/* External interrupt pins in IRL mode */
@@ -909,10 +905,10 @@ static struct intc_vect vectors_irl4567[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7786-irl0123", vectors_irl0123,
- NULL, mask_registers, NULL, NULL);
+ NULL, sh7786_mask_registers, NULL, NULL);
static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7786-irl4567", vectors_irl4567,
- NULL, mask_registers, NULL, NULL);
+ NULL, sh7786_mask_registers, NULL, NULL);
#define INTC_ICR0 0xfe410000
#define INTC_INTMSK0 CnINTMSK0
@@ -920,19 +916,6 @@ static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7786-irl4567", vectors_irl4567,
#define INTC_INTMSK2 INTMSK2
#define INTC_INTMSKCLR1 CnINTMSKCLR1
#define INTC_INTMSKCLR2 INTMSKCLR2
-#define INTC_USERIMASK 0xfe411000
-
-#ifdef CONFIG_INTC_BALANCING
-unsigned int irq_lookup(unsigned int irq)
-{
- return __raw_readl(INTACK) & 1 ? irq : NO_IRQ_IGNORE;
-}
-
-void irq_finish(unsigned int irq)
-{
- __raw_writel(irq2evt(irq), INTACKCLR);
-}
-#endif
void __init plat_irq_setup(void)
{
@@ -946,8 +929,7 @@ void __init plat_irq_setup(void)
/* select IRL mode for IRL3-0 + IRL7-4 */
__raw_writel(__raw_readl(INTC_ICR0) & ~0x00c00000, INTC_ICR0);
- register_intc_controller(&intc_desc);
- register_intc_userimask(INTC_USERIMASK);
+ register_intc_controller(&sh7786_intc_desc);
}
void __init plat_irq_setup_pins(int mode)
@@ -991,3 +973,39 @@ void __init plat_irq_setup_pins(int mode)
void __init plat_mem_setup(void)
{
}
+
+static int __init sh7786_devices_setup(void)
+{
+ int ret, irq;
+
+ sh7786_usb_setup();
+
+ /*
+ * De-mux SCIF1 IRQs if possible
+ */
+ irq = intc_irq_lookup(sh7786_intc_desc.name, TXI1);
+ if (irq > 0) {
+ scif1_platform_data.irqs[SCIx_TXI_IRQ] = irq;
+ scif1_platform_data.irqs[SCIx_ERI_IRQ] =
+ intc_irq_lookup(sh7786_intc_desc.name, ERI1);
+ scif1_platform_data.irqs[SCIx_BRI_IRQ] =
+ intc_irq_lookup(sh7786_intc_desc.name, BRI1);
+ scif1_platform_data.irqs[SCIx_RXI_IRQ] =
+ intc_irq_lookup(sh7786_intc_desc.name, RXI1);
+ }
+
+ ret = platform_add_devices(sh7786_early_devices,
+ ARRAY_SIZE(sh7786_early_devices));
+ if (unlikely(ret != 0))
+ return ret;
+
+ return platform_add_devices(sh7786_devices,
+ ARRAY_SIZE(sh7786_devices));
+}
+arch_initcall(sh7786_devices_setup);
+
+void __init plat_early_device_setup(void)
+{
+ early_platform_add_devices(sh7786_early_devices,
+ ARRAY_SIZE(sh7786_early_devices));
+}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index 9158bc5ea38b..013f0b144489 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -1,7 +1,7 @@
/*
* SH-X3 Prototype Setup
*
- * Copyright (C) 2007 - 2009 Paul Mundt
+ * Copyright (C) 2007 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -12,7 +12,9 @@
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/io.h>
+#include <linux/gpio.h>
#include <linux/sh_timer.h>
+#include <cpu/shx3.h>
#include <asm/mmzone.h>
/*
@@ -354,6 +356,10 @@ static struct intc_group groups[] __initdata = {
DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
};
+#define INT2DISTCR0 0xfe4108a0
+#define INT2DISTCR1 0xfe4108a4
+#define INT2DISTCR2 0xfe4108a8
+
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfe410030, 0xfe410050, 32, /* CnINTMSK0 / CnINTMSKCLR0 */
{ IRQ0, IRQ1, IRQ2, IRQ3 } },
@@ -363,20 +369,23 @@ static struct intc_mask_reg mask_registers[] __initdata = {
{ FE1, FE0, 0, ATAPI, VCORE0, VIN1, VIN0, IIC,
DU, GPIO3, GPIO2, GPIO1, GPIO0, PAM, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, /* HUDI bits ignored */
- 0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, } },
+ 0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, },
+ INTC_SMP_BALANCING(INT2DISTCR0) },
{ 0xfe410830, 0xfe410860, 32, /* CnINT2MSK1 / CnINT2MSKCLR1 */
{ 0, 0, 0, 0, DTU3, DTU2, DTU1, DTU0, /* IRM bits ignored */
PCII9, PCII8, PCII7, PCII6, PCII5, PCII4, PCII3, PCII2,
PCII1, PCII0, DMAC1_DMAE, DMAC1_DMINT11,
DMAC1_DMINT10, DMAC1_DMINT9, DMAC1_DMINT8, DMAC1_DMINT7,
DMAC1_DMINT6, DMAC0_DMAE, DMAC0_DMINT5, DMAC0_DMINT4,
- DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 } },
+ DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 },
+ INTC_SMP_BALANCING(INT2DISTCR1) },
{ 0xfe410840, 0xfe410870, 32, /* CnINT2MSK2 / CnINT2MSKCLR2 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
SCIF3_TXI, SCIF3_BRI, SCIF3_RXI, SCIF3_ERI,
SCIF2_TXI, SCIF2_BRI, SCIF2_RXI, SCIF2_ERI,
SCIF1_TXI, SCIF1_BRI, SCIF1_RXI, SCIF1_ERI,
- SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI } },
+ SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI },
+ INTC_SMP_BALANCING(INT2DISTCR2) },
};
static struct intc_prio_reg prio_registers[] __initdata = {
@@ -433,11 +442,33 @@ static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
void __init plat_irq_setup_pins(int mode)
{
+ int ret = 0;
+
switch (mode) {
case IRQ_MODE_IRQ:
+ ret |= gpio_request(GPIO_FN_IRQ3, intc_desc_irq.name);
+ ret |= gpio_request(GPIO_FN_IRQ2, intc_desc_irq.name);
+ ret |= gpio_request(GPIO_FN_IRQ1, intc_desc_irq.name);
+ ret |= gpio_request(GPIO_FN_IRQ0, intc_desc_irq.name);
+
+ if (unlikely(ret)) {
+ pr_err("Failed to set IRQ mode\n");
+ return;
+ }
+
register_intc_controller(&intc_desc_irq);
break;
case IRQ_MODE_IRL3210:
+ ret |= gpio_request(GPIO_FN_IRL3, intc_desc_irl.name);
+ ret |= gpio_request(GPIO_FN_IRL2, intc_desc_irl.name);
+ ret |= gpio_request(GPIO_FN_IRL1, intc_desc_irl.name);
+ ret |= gpio_request(GPIO_FN_IRL0, intc_desc_irl.name);
+
+ if (unlikely(ret)) {
+ pr_err("Failed to set IRL mode\n");
+ return;
+ }
+
register_intc_controller(&intc_desc_irl);
break;
default:
@@ -447,6 +478,9 @@ void __init plat_irq_setup_pins(int mode)
void __init plat_irq_setup(void)
{
+ reserve_intc_vectors(vectors_irq, ARRAY_SIZE(vectors_irq));
+ reserve_intc_vectors(vectors_irl, ARRAY_SIZE(vectors_irl));
+
register_intc_controller(&intc_desc);
}
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S
index 6e35f012cc03..7db248936b60 100644
--- a/arch/sh/kernel/head_32.S
+++ b/arch/sh/kernel/head_32.S
@@ -330,7 +330,7 @@ ENTRY(_stext)
#if defined(CONFIG_CPU_SH2)
1: .long 0x000000F0 ! IMASK=0xF
#else
-1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
+1: .long 0x500080F0 ! MD=1, RB=0, BL=1, FD=1, IMASK=0xF
#endif
ENTRY(stack_start)
2: .long init_thread_union+THREAD_SIZE
diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c
index 2947d2bd1291..32c385ef1011 100644
--- a/arch/sh/kernel/io_trapped.c
+++ b/arch/sh/kernel/io_trapped.c
@@ -291,7 +291,7 @@ int handle_trapped_io(struct pt_regs *regs, unsigned long address)
}
tmp = handle_unaligned_access(instruction, regs,
- &trapped_io_access, 1);
+ &trapped_io_access, 1, address);
set_fs(oldfs);
return tmp == 0;
}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index ae5bac39b896..9dc447db8a44 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -283,6 +283,8 @@ void __init init_IRQ(void)
if (sh_mv.mv_init_irq)
sh_mv.mv_init_irq();
+ intc_finalize();
+
irq_ctx_init(smp_processor_id());
}
diff --git a/arch/sh/kernel/kdebugfs.c b/arch/sh/kernel/kdebugfs.c
new file mode 100644
index 000000000000..e11c30bb100c
--- /dev/null
+++ b/arch/sh/kernel/kdebugfs.c
@@ -0,0 +1,16 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+
+struct dentry *arch_debugfs_dir;
+EXPORT_SYMBOL(arch_debugfs_dir);
+
+static int __init arch_kdebugfs_init(void)
+{
+ arch_debugfs_dir = debugfs_create_dir("sh", NULL);
+ if (!arch_debugfs_dir)
+ return -ENOMEM;
+
+ return 0;
+}
+arch_initcall(arch_kdebugfs_init);
diff --git a/arch/sh/kernel/kprobes.c b/arch/sh/kernel/kprobes.c
index 4049d99f76e1..1208b09e95c3 100644
--- a/arch/sh/kernel/kprobes.c
+++ b/arch/sh/kernel/kprobes.c
@@ -20,9 +20,9 @@
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
-static struct kprobe saved_current_opcode;
-static struct kprobe saved_next_opcode;
-static struct kprobe saved_next_opcode2;
+static DEFINE_PER_CPU(struct kprobe, saved_current_opcode);
+static DEFINE_PER_CPU(struct kprobe, saved_next_opcode);
+static DEFINE_PER_CPU(struct kprobe, saved_next_opcode2);
#define OPCODE_JMP(x) (((x) & 0xF0FF) == 0x402b)
#define OPCODE_JSR(x) (((x) & 0xF0FF) == 0x400b)
@@ -102,16 +102,21 @@ int __kprobes kprobe_handle_illslot(unsigned long pc)
void __kprobes arch_remove_kprobe(struct kprobe *p)
{
- if (saved_next_opcode.addr != 0x0) {
+ struct kprobe *saved = &__get_cpu_var(saved_next_opcode);
+
+ if (saved->addr) {
arch_disarm_kprobe(p);
- arch_disarm_kprobe(&saved_next_opcode);
- saved_next_opcode.addr = 0x0;
- saved_next_opcode.opcode = 0x0;
-
- if (saved_next_opcode2.addr != 0x0) {
- arch_disarm_kprobe(&saved_next_opcode2);
- saved_next_opcode2.addr = 0x0;
- saved_next_opcode2.opcode = 0x0;
+ arch_disarm_kprobe(saved);
+
+ saved->addr = NULL;
+ saved->opcode = 0;
+
+ saved = &__get_cpu_var(saved_next_opcode2);
+ if (saved->addr) {
+ arch_disarm_kprobe(saved);
+
+ saved->addr = NULL;
+ saved->opcode = 0;
}
}
}
@@ -141,57 +146,59 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
*/
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
- kprobe_opcode_t *addr = NULL;
- saved_current_opcode.addr = (kprobe_opcode_t *) (regs->pc);
- addr = saved_current_opcode.addr;
+ __get_cpu_var(saved_current_opcode).addr = (kprobe_opcode_t *)regs->pc;
if (p != NULL) {
+ struct kprobe *op1, *op2;
+
arch_disarm_kprobe(p);
+ op1 = &__get_cpu_var(saved_next_opcode);
+ op2 = &__get_cpu_var(saved_next_opcode2);
+
if (OPCODE_JSR(p->opcode) || OPCODE_JMP(p->opcode)) {
unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
- saved_next_opcode.addr =
- (kprobe_opcode_t *) regs->regs[reg_nr];
+ op1->addr = (kprobe_opcode_t *) regs->regs[reg_nr];
} else if (OPCODE_BRA(p->opcode) || OPCODE_BSR(p->opcode)) {
unsigned long disp = (p->opcode & 0x0FFF);
- saved_next_opcode.addr =
+ op1->addr =
(kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
} else if (OPCODE_BRAF(p->opcode) || OPCODE_BSRF(p->opcode)) {
unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
- saved_next_opcode.addr =
+ op1->addr =
(kprobe_opcode_t *) (regs->pc + 4 +
regs->regs[reg_nr]);
} else if (OPCODE_RTS(p->opcode)) {
- saved_next_opcode.addr = (kprobe_opcode_t *) regs->pr;
+ op1->addr = (kprobe_opcode_t *) regs->pr;
} else if (OPCODE_BF(p->opcode) || OPCODE_BT(p->opcode)) {
unsigned long disp = (p->opcode & 0x00FF);
/* case 1 */
- saved_next_opcode.addr = p->addr + 1;
+ op1->addr = p->addr + 1;
/* case 2 */
- saved_next_opcode2.addr =
+ op2->addr =
(kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
- saved_next_opcode2.opcode = *(saved_next_opcode2.addr);
- arch_arm_kprobe(&saved_next_opcode2);
+ op2->opcode = *(op2->addr);
+ arch_arm_kprobe(op2);
} else if (OPCODE_BF_S(p->opcode) || OPCODE_BT_S(p->opcode)) {
unsigned long disp = (p->opcode & 0x00FF);
/* case 1 */
- saved_next_opcode.addr = p->addr + 2;
+ op1->addr = p->addr + 2;
/* case 2 */
- saved_next_opcode2.addr =
+ op2->addr =
(kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
- saved_next_opcode2.opcode = *(saved_next_opcode2.addr);
- arch_arm_kprobe(&saved_next_opcode2);
+ op2->opcode = *(op2->addr);
+ arch_arm_kprobe(op2);
} else {
- saved_next_opcode.addr = p->addr + 1;
+ op1->addr = p->addr + 1;
}
- saved_next_opcode.opcode = *(saved_next_opcode.addr);
- arch_arm_kprobe(&saved_next_opcode);
+ op1->opcode = *(op1->addr);
+ arch_arm_kprobe(op1);
}
}
@@ -376,21 +383,23 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
cur->post_handler(cur, regs, 0);
}
- if (saved_next_opcode.addr != 0x0) {
- arch_disarm_kprobe(&saved_next_opcode);
- saved_next_opcode.addr = 0x0;
- saved_next_opcode.opcode = 0x0;
+ p = &__get_cpu_var(saved_next_opcode);
+ if (p->addr) {
+ arch_disarm_kprobe(p);
+ p->addr = NULL;
+ p->opcode = 0;
- addr = saved_current_opcode.addr;
- saved_current_opcode.addr = 0x0;
+ addr = __get_cpu_var(saved_current_opcode).addr;
+ __get_cpu_var(saved_current_opcode).addr = NULL;
p = get_kprobe(addr);
arch_arm_kprobe(p);
- if (saved_next_opcode2.addr != 0x0) {
- arch_disarm_kprobe(&saved_next_opcode2);
- saved_next_opcode2.addr = 0x0;
- saved_next_opcode2.opcode = 0x0;
+ p = &__get_cpu_var(saved_next_opcode2);
+ if (p->addr) {
+ arch_disarm_kprobe(p);
+ p->addr = NULL;
+ p->opcode = 0;
}
}
@@ -572,14 +581,5 @@ static struct kprobe trampoline_p = {
int __init arch_init_kprobes(void)
{
- saved_next_opcode.addr = 0x0;
- saved_next_opcode.opcode = 0x0;
-
- saved_current_opcode.addr = 0x0;
- saved_current_opcode.opcode = 0x0;
-
- saved_next_opcode2.addr = 0x0;
- saved_next_opcode2.opcode = 0x0;
-
return register_kprobe(&trampoline_p);
}
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
new file mode 100644
index 000000000000..0a05983633ca
--- /dev/null
+++ b/arch/sh/kernel/ptrace.c
@@ -0,0 +1,33 @@
+#include <linux/ptrace.h>
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name: the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+ const struct pt_regs_offset *roff;
+ for (roff = regoffset_table; roff->name != NULL; roff++)
+ if (!strcmp(roff->name, name))
+ return roff->offset;
+ return -EINVAL;
+}
+
+/**
+ * regs_query_register_name() - query register name from its offset
+ * @offset: the offset of a register in struct pt_regs.
+ *
+ * regs_query_register_name() returns the name of a register from its
+ * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
+ */
+const char *regs_query_register_name(unsigned int offset)
+{
+ const struct pt_regs_offset *roff;
+ for (roff = regoffset_table; roff->name != NULL; roff++)
+ if (roff->offset == offset)
+ return roff->name;
+ return NULL;
+}
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index 6c4bbba2a675..2cd42b58cb20 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -274,6 +274,33 @@ static int dspregs_active(struct task_struct *target,
}
#endif
+const struct pt_regs_offset regoffset_table[] = {
+ REGS_OFFSET_NAME(0),
+ REGS_OFFSET_NAME(1),
+ REGS_OFFSET_NAME(2),
+ REGS_OFFSET_NAME(3),
+ REGS_OFFSET_NAME(4),
+ REGS_OFFSET_NAME(5),
+ REGS_OFFSET_NAME(6),
+ REGS_OFFSET_NAME(7),
+ REGS_OFFSET_NAME(8),
+ REGS_OFFSET_NAME(9),
+ REGS_OFFSET_NAME(10),
+ REGS_OFFSET_NAME(11),
+ REGS_OFFSET_NAME(12),
+ REGS_OFFSET_NAME(13),
+ REGS_OFFSET_NAME(14),
+ REGS_OFFSET_NAME(15),
+ REG_OFFSET_NAME(pc),
+ REG_OFFSET_NAME(pr),
+ REG_OFFSET_NAME(sr),
+ REG_OFFSET_NAME(gbr),
+ REG_OFFSET_NAME(mach),
+ REG_OFFSET_NAME(macl),
+ REG_OFFSET_NAME(tra),
+ REG_OFFSET_END,
+};
+
/*
* These are our native regset flavours.
*/
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
index 5fd644da7f02..e0fb065914aa 100644
--- a/arch/sh/kernel/ptrace_64.c
+++ b/arch/sh/kernel/ptrace_64.c
@@ -20,7 +20,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
+#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
@@ -252,6 +252,85 @@ static int fpregs_active(struct task_struct *target,
}
#endif
+const struct pt_regs_offset regoffset_table[] = {
+ REG_OFFSET_NAME(pc),
+ REG_OFFSET_NAME(sr),
+ REG_OFFSET_NAME(syscall_nr),
+ REGS_OFFSET_NAME(0),
+ REGS_OFFSET_NAME(1),
+ REGS_OFFSET_NAME(2),
+ REGS_OFFSET_NAME(3),
+ REGS_OFFSET_NAME(4),
+ REGS_OFFSET_NAME(5),
+ REGS_OFFSET_NAME(6),
+ REGS_OFFSET_NAME(7),
+ REGS_OFFSET_NAME(8),
+ REGS_OFFSET_NAME(9),
+ REGS_OFFSET_NAME(10),
+ REGS_OFFSET_NAME(11),
+ REGS_OFFSET_NAME(12),
+ REGS_OFFSET_NAME(13),
+ REGS_OFFSET_NAME(14),
+ REGS_OFFSET_NAME(15),
+ REGS_OFFSET_NAME(16),
+ REGS_OFFSET_NAME(17),
+ REGS_OFFSET_NAME(18),
+ REGS_OFFSET_NAME(19),
+ REGS_OFFSET_NAME(20),
+ REGS_OFFSET_NAME(21),
+ REGS_OFFSET_NAME(22),
+ REGS_OFFSET_NAME(23),
+ REGS_OFFSET_NAME(24),
+ REGS_OFFSET_NAME(25),
+ REGS_OFFSET_NAME(26),
+ REGS_OFFSET_NAME(27),
+ REGS_OFFSET_NAME(28),
+ REGS_OFFSET_NAME(29),
+ REGS_OFFSET_NAME(30),
+ REGS_OFFSET_NAME(31),
+ REGS_OFFSET_NAME(32),
+ REGS_OFFSET_NAME(33),
+ REGS_OFFSET_NAME(34),
+ REGS_OFFSET_NAME(35),
+ REGS_OFFSET_NAME(36),
+ REGS_OFFSET_NAME(37),
+ REGS_OFFSET_NAME(38),
+ REGS_OFFSET_NAME(39),
+ REGS_OFFSET_NAME(40),
+ REGS_OFFSET_NAME(41),
+ REGS_OFFSET_NAME(42),
+ REGS_OFFSET_NAME(43),
+ REGS_OFFSET_NAME(44),
+ REGS_OFFSET_NAME(45),
+ REGS_OFFSET_NAME(46),
+ REGS_OFFSET_NAME(47),
+ REGS_OFFSET_NAME(48),
+ REGS_OFFSET_NAME(49),
+ REGS_OFFSET_NAME(50),
+ REGS_OFFSET_NAME(51),
+ REGS_OFFSET_NAME(52),
+ REGS_OFFSET_NAME(53),
+ REGS_OFFSET_NAME(54),
+ REGS_OFFSET_NAME(55),
+ REGS_OFFSET_NAME(56),
+ REGS_OFFSET_NAME(57),
+ REGS_OFFSET_NAME(58),
+ REGS_OFFSET_NAME(59),
+ REGS_OFFSET_NAME(60),
+ REGS_OFFSET_NAME(61),
+ REGS_OFFSET_NAME(62),
+ REGS_OFFSET_NAME(63),
+ TREGS_OFFSET_NAME(0),
+ TREGS_OFFSET_NAME(1),
+ TREGS_OFFSET_NAME(2),
+ TREGS_OFFSET_NAME(3),
+ TREGS_OFFSET_NAME(4),
+ TREGS_OFFSET_NAME(5),
+ TREGS_OFFSET_NAME(6),
+ TREGS_OFFSET_NAME(7),
+ REG_OFFSET_END,
+};
+
/*
* These are our native regset flavours.
*/
@@ -395,10 +474,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
asmlinkage int sh64_ptrace(long request, long pid, long addr, long data)
{
#define WPC_DBRMODE 0x0d104008
- static int first_call = 1;
+ static unsigned long first_call;
- lock_kernel();
- if (first_call) {
+ if (!test_and_set_bit(0, &first_call)) {
/* Set WPC.DBRMODE to 0. This makes all debug events get
* delivered through RESVEC, i.e. into the handlers in entry.S.
* (If the kernel was downloaded using a remote gdb, WPC.DBRMODE
@@ -408,9 +486,7 @@ asmlinkage int sh64_ptrace(long request, long pid, long addr, long data)
* the remote gdb.) */
printk("DBRMODE set to 0 to permit native debugging\n");
poke_real_address_q(WPC_DBRMODE, 0);
- first_call = 0;
}
- unlock_kernel();
return sys_ptrace(request, pid, addr, data);
}
diff --git a/arch/sh/kernel/reboot.c b/arch/sh/kernel/reboot.c
index b1fca66bb92e..ca6a5ca64015 100644
--- a/arch/sh/kernel/reboot.c
+++ b/arch/sh/kernel/reboot.c
@@ -9,6 +9,7 @@
#include <asm/addrspace.h>
#include <asm/reboot.h>
#include <asm/system.h>
+#include <asm/tlbflush.h>
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
@@ -25,6 +26,9 @@ static void native_machine_restart(char * __unused)
{
local_irq_disable();
+ /* Destroy all of the TLBs in preparation for reset by MMU */
+ __flush_tlb_global();
+
/* Address error with SR.BL=1 first. */
trigger_address_error();
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index e769401a78ba..4e278467f76c 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -24,7 +24,6 @@
#include <linux/module.h>
#include <linux/smp.h>
#include <linux/err.h>
-#include <linux/debugfs.h>
#include <linux/crash_dump.h>
#include <linux/mmzone.h>
#include <linux/clk.h>
@@ -136,8 +135,9 @@ void __init check_for_initrd(void)
goto disable;
}
- if (unlikely(start < PAGE_OFFSET)) {
- pr_err("initrd start < PAGE_OFFSET\n");
+ if (unlikely(start < __MEMORY_START)) {
+ pr_err("initrd start (%08lx) < __MEMORY_START(%x)\n",
+ start, __MEMORY_START);
goto disable;
}
@@ -158,7 +158,7 @@ void __init check_for_initrd(void)
/*
* Address sanitization
*/
- initrd_start = (unsigned long)__va(__pa(start));
+ initrd_start = (unsigned long)__va(start);
initrd_end = initrd_start + INITRD_SIZE;
memblock_reserve(__pa(initrd_start), INITRD_SIZE);
@@ -458,17 +458,3 @@ const struct seq_operations cpuinfo_op = {
.show = show_cpuinfo,
};
#endif /* CONFIG_PROC_FS */
-
-struct dentry *sh_debugfs_root;
-
-static int __init sh_debugfs_init(void)
-{
- sh_debugfs_root = debugfs_create_dir("sh", NULL);
- if (!sh_debugfs_root)
- return -ENOMEM;
- if (IS_ERR(sh_debugfs_root))
- return PTR_ERR(sh_debugfs_root);
-
- return 0;
-}
-arch_initcall(sh_debugfs_init);
diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S
index 19fd11dd9871..e872e81add8a 100644
--- a/arch/sh/kernel/syscalls_32.S
+++ b/arch/sh/kernel/syscalls_32.S
@@ -353,3 +353,25 @@ ENTRY(sys_call_table)
.long sys_pwritev
.long sys_rt_tgsigqueueinfo /* 335 */
.long sys_perf_event_open
+ .long sys_fanotify_init
+ .long sys_fanotify_mark
+ .long sys_prlimit64
+ /* Broken-out socket family */
+ .long sys_socket /* 340 */
+ .long sys_bind
+ .long sys_connect
+ .long sys_listen
+ .long sys_accept
+ .long sys_getsockname /* 345 */
+ .long sys_getpeername
+ .long sys_socketpair
+ .long sys_send
+ .long sys_sendto
+ .long sys_recv /* 350 */
+ .long sys_recvfrom
+ .long sys_shutdown
+ .long sys_setsockopt
+ .long sys_getsockopt
+ .long sys_sendmsg /* 355 */
+ .long sys_recvmsg
+ .long sys_recvmmsg
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
index 2048a20d7c80..66585708ce90 100644
--- a/arch/sh/kernel/syscalls_64.S
+++ b/arch/sh/kernel/syscalls_64.S
@@ -393,3 +393,6 @@ sys_call_table:
.long sys_perf_event_open
.long sys_recvmmsg /* 365 */
.long sys_accept4
+ .long sys_fanotify_init
+ .long sys_fanotify_mark
+ .long sys_prlimit64
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index c3d86fa71ddf..3484c2f65aba 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -5,7 +5,7 @@
* SuperH version: Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf
* Copyright (C) 2000 David Howells
- * Copyright (C) 2002 - 2007 Paul Mundt
+ * Copyright (C) 2002 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -26,6 +26,7 @@
#include <linux/limits.h>
#include <linux/sysfs.h>
#include <linux/uaccess.h>
+#include <linux/perf_event.h>
#include <asm/system.h>
#include <asm/alignment.h>
#include <asm/fpu.h>
@@ -369,7 +370,8 @@ static inline int handle_delayslot(struct pt_regs *regs,
#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
- struct mem_access *ma, int expected)
+ struct mem_access *ma, int expected,
+ unsigned long address)
{
u_int rm;
int ret, index;
@@ -383,9 +385,18 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
index = (instruction>>8)&15; /* 0x0F00 */
rm = regs->regs[index];
- /* shout about fixups */
- if (!expected)
+ /*
+ * Log the unexpected fixups, and then pass them on to perf.
+ *
+ * We intentionally don't report the expected cases to perf as
+ * otherwise the trapped I/O case will skew the results too much
+ * to be useful.
+ */
+ if (!expected) {
unaligned_fixups_notify(current, instruction, regs);
+ perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0,
+ regs, address);
+ }
ret = -EFAULT;
switch (instruction&0xF000) {
@@ -574,7 +585,8 @@ fixup:
set_fs(USER_DS);
tmp = handle_unaligned_access(instruction, regs,
- &user_mem_access, 0);
+ &user_mem_access, 0,
+ address);
set_fs(oldfs);
if (tmp == 0)
@@ -607,8 +619,8 @@ uspace_segv:
unaligned_fixups_notify(current, instruction, regs);
- handle_unaligned_access(instruction, regs,
- &user_mem_access, 0);
+ handle_unaligned_access(instruction, regs, &user_mem_access,
+ 0, address);
set_fs(oldfs);
}
}
@@ -802,6 +814,9 @@ void __cpuinit per_cpu_trap_init(void)
: /* no output */
: "r" (&vbr_base)
: "memory");
+
+ /* disable exception blocking now when the vbr has been setup */
+ clear_bl_bit();
}
void *set_exception_table_vec(unsigned int vec, void *handler)
diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c
index e67e140bf1f6..6713ca97e553 100644
--- a/arch/sh/kernel/traps_64.c
+++ b/arch/sh/kernel/traps_64.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/sysctl.h>
#include <linux/module.h>
+#include <linux/perf_event.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -50,7 +51,7 @@ asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \
do_unhandled_exception(trapnr, signr, str, __stringify(name), error_code, regs, current); \
}
-spinlock_t die_lock;
+static DEFINE_SPINLOCK(die_lock);
void die(const char * str, struct pt_regs * regs, long err)
{
@@ -433,6 +434,8 @@ static int misaligned_load(struct pt_regs *regs,
return error;
}
+ perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
+
destreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
@@ -509,6 +512,8 @@ static int misaligned_store(struct pt_regs *regs,
return error;
}
+ perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
+
srcreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
@@ -583,6 +588,8 @@ static int misaligned_fpu_load(struct pt_regs *regs,
return error;
}
+ perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
+
destreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
@@ -658,6 +665,8 @@ static int misaligned_fpu_store(struct pt_regs *regs,
return error;
}
+ perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
+
srcreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index dab4d2129812..7b95f29e3174 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -30,4 +30,4 @@ lib-$(CONFIG_MMU) += copy_page.o __clear_user.o
lib-$(CONFIG_MCOUNT) += mcount.o
lib-y += $(memcpy-y) $(memset-y) $(udivsi3-y)
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c
index 1fcdb1220975..f76a5090d5d1 100644
--- a/arch/sh/math-emu/math.c
+++ b/arch/sh/math-emu/math.c
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/signal.h>
+#include <linux/perf_event.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -619,6 +620,8 @@ int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
struct task_struct *tsk = current;
struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu);
+ perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0);
+
if (!(task_thread_info(tsk)->status & TS_USEDFPU)) {
/* initialize once. */
fpu_init(fpu);
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 1445ca6257df..09370392aff1 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -168,6 +168,10 @@ config IOREMAP_FIXED
config UNCACHED_MAPPING
bool
+config HAVE_SRAM_POOL
+ bool
+ select GENERIC_ALLOCATOR
+
choice
prompt "Kernel page size"
default PAGE_SIZE_4KB
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 53f7c684afb2..ab89ea4f9414 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_PMB) += pmb.o
obj-$(CONFIG_NUMA) += numa.o
obj-$(CONFIG_IOREMAP_FIXED) += ioremap_fixed.o
obj-$(CONFIG_UNCACHED_MAPPING) += uncached.o
+obj-$(CONFIG_HAVE_SRAM_POOL) += sram.o
# Special flags for fault_64.o. This puts restrictions on the number of
# caller-save registers that the compiler can target when building this file.
@@ -66,4 +67,4 @@ CFLAGS_fault_64.o += -ffixed-r7 \
-ffixed-r60 -ffixed-r61 -ffixed-r62 \
-fomit-frame-pointer
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff --git a/arch/sh/mm/asids-debugfs.c b/arch/sh/mm/asids-debugfs.c
index cd8c3bf39b5a..74c03ecc4871 100644
--- a/arch/sh/mm/asids-debugfs.c
+++ b/arch/sh/mm/asids-debugfs.c
@@ -63,7 +63,7 @@ static int __init asids_debugfs_init(void)
{
struct dentry *asids_dentry;
- asids_dentry = debugfs_create_file("asids", S_IRUSR, sh_debugfs_root,
+ asids_dentry = debugfs_create_file("asids", S_IRUSR, arch_debugfs_dir,
NULL, &asids_debugfs_fops);
if (!asids_dentry)
return -ENOMEM;
diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c
index 690ed010d002..52411462c409 100644
--- a/arch/sh/mm/cache-debugfs.c
+++ b/arch/sh/mm/cache-debugfs.c
@@ -126,25 +126,19 @@ static int __init cache_debugfs_init(void)
{
struct dentry *dcache_dentry, *icache_dentry;
- dcache_dentry = debugfs_create_file("dcache", S_IRUSR, sh_debugfs_root,
+ dcache_dentry = debugfs_create_file("dcache", S_IRUSR, arch_debugfs_dir,
(unsigned int *)CACHE_TYPE_DCACHE,
&cache_debugfs_fops);
if (!dcache_dentry)
return -ENOMEM;
- if (IS_ERR(dcache_dentry))
- return PTR_ERR(dcache_dentry);
- icache_dentry = debugfs_create_file("icache", S_IRUSR, sh_debugfs_root,
+ icache_dentry = debugfs_create_file("icache", S_IRUSR, arch_debugfs_dir,
(unsigned int *)CACHE_TYPE_ICACHE,
&cache_debugfs_fops);
if (!icache_dentry) {
debugfs_remove(dcache_dentry);
return -ENOMEM;
}
- if (IS_ERR(icache_dentry)) {
- debugfs_remove(dcache_dentry);
- return PTR_ERR(icache_dentry);
- }
return 0;
}
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index c86a08540258..038793286990 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -38,11 +38,12 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
void *ret, *ret_nocache;
int order = get_order(size);
+ gfp |= __GFP_ZERO;
+
ret = (void *)__get_free_pages(gfp, order);
if (!ret)
return NULL;
- memset(ret, 0, size);
/*
* Pages from the page allocator may have data present in
* cache. So flush the cache before using uncached memory.
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 552bea5113f5..3385b28acaac 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -47,7 +47,6 @@ static pte_t *__get_pte_phys(unsigned long addr)
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
- pte_t *pte;
pgd = pgd_offset_k(addr);
if (pgd_none(*pgd)) {
@@ -67,8 +66,7 @@ static pte_t *__get_pte_phys(unsigned long addr)
return NULL;
}
- pte = pte_offset_kernel(pmd, addr);
- return pte;
+ return pte_offset_kernel(pmd, addr);
}
static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
@@ -125,13 +123,45 @@ void __clear_fixmap(enum fixed_addresses idx, pgprot_t prot)
clear_pte_phys(address, prot);
}
+static pmd_t * __init one_md_table_init(pud_t *pud)
+{
+ if (pud_none(*pud)) {
+ pmd_t *pmd;
+
+ pmd = alloc_bootmem_pages(PAGE_SIZE);
+ pud_populate(&init_mm, pud, pmd);
+ BUG_ON(pmd != pmd_offset(pud, 0));
+ }
+
+ return pmd_offset(pud, 0);
+}
+
+static pte_t * __init one_page_table_init(pmd_t *pmd)
+{
+ if (pmd_none(*pmd)) {
+ pte_t *pte;
+
+ pte = alloc_bootmem_pages(PAGE_SIZE);
+ pmd_populate_kernel(&init_mm, pmd, pte);
+ BUG_ON(pte != pte_offset_kernel(pmd, 0));
+ }
+
+ return pte_offset_kernel(pmd, 0);
+}
+
+static pte_t * __init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
+ unsigned long vaddr, pte_t *lastpte)
+{
+ return pte;
+}
+
void __init page_table_range_init(unsigned long start, unsigned long end,
pgd_t *pgd_base)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
- pte_t *pte;
+ pte_t *pte = NULL;
int i, j, k;
unsigned long vaddr;
@@ -144,19 +174,13 @@ void __init page_table_range_init(unsigned long start, unsigned long end,
for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
pud = (pud_t *)pgd;
for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) {
-#ifdef __PAGETABLE_PMD_FOLDED
- pmd = (pmd_t *)pud;
-#else
- pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
- pud_populate(&init_mm, pud, pmd);
+ pmd = one_md_table_init(pud);
+#ifndef __PAGETABLE_PMD_FOLDED
pmd += k;
#endif
for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) {
- if (pmd_none(*pmd)) {
- pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
- pmd_populate_kernel(&init_mm, pmd, pte);
- BUG_ON(pte != pte_offset_kernel(pmd, 0));
- }
+ pte = page_table_kmap_check(one_page_table_init(pmd),
+ pmd, vaddr, pte);
vaddr += PMD_SIZE;
}
k = 0;
diff --git a/arch/sh/mm/nommu.c b/arch/sh/mm/nommu.c
index 7694f50c9034..36312d254faf 100644
--- a/arch/sh/mm/nommu.c
+++ b/arch/sh/mm/nommu.c
@@ -67,6 +67,10 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
BUG();
}
+void __flush_tlb_global(void)
+{
+}
+
void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
{
}
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index 6379091a1647..b20b1b3eee4b 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -40,7 +40,7 @@ struct pmb_entry {
unsigned long flags;
unsigned long size;
- spinlock_t lock;
+ raw_spinlock_t lock;
/*
* 0 .. NR_PMB_ENTRIES for specific entry selection, or
@@ -265,7 +265,7 @@ static struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
memset(pmbe, 0, sizeof(struct pmb_entry));
- spin_lock_init(&pmbe->lock);
+ raw_spin_lock_init(&pmbe->lock);
pmbe->vpn = vpn;
pmbe->ppn = ppn;
@@ -327,9 +327,9 @@ static void set_pmb_entry(struct pmb_entry *pmbe)
{
unsigned long flags;
- spin_lock_irqsave(&pmbe->lock, flags);
+ raw_spin_lock_irqsave(&pmbe->lock, flags);
__set_pmb_entry(pmbe);
- spin_unlock_irqrestore(&pmbe->lock, flags);
+ raw_spin_unlock_irqrestore(&pmbe->lock, flags);
}
#endif /* CONFIG_PM */
@@ -368,7 +368,7 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys,
return PTR_ERR(pmbe);
}
- spin_lock_irqsave(&pmbe->lock, flags);
+ raw_spin_lock_irqsave(&pmbe->lock, flags);
pmbe->size = pmb_sizes[i].size;
@@ -383,9 +383,10 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys,
* entries for easier tear-down.
*/
if (likely(pmbp)) {
- spin_lock(&pmbp->lock);
+ raw_spin_lock_nested(&pmbp->lock,
+ SINGLE_DEPTH_NESTING);
pmbp->link = pmbe;
- spin_unlock(&pmbp->lock);
+ raw_spin_unlock(&pmbp->lock);
}
pmbp = pmbe;
@@ -398,7 +399,7 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys,
i--;
mapped++;
- spin_unlock_irqrestore(&pmbe->lock, flags);
+ raw_spin_unlock_irqrestore(&pmbe->lock, flags);
}
} while (size >= SZ_16M);
@@ -627,15 +628,14 @@ static void __init pmb_synchronize(void)
continue;
}
- spin_lock_irqsave(&pmbe->lock, irqflags);
+ raw_spin_lock_irqsave(&pmbe->lock, irqflags);
for (j = 0; j < ARRAY_SIZE(pmb_sizes); j++)
if (pmb_sizes[j].flag == size)
pmbe->size = pmb_sizes[j].size;
if (pmbp) {
- spin_lock(&pmbp->lock);
-
+ raw_spin_lock_nested(&pmbp->lock, SINGLE_DEPTH_NESTING);
/*
* Compare the previous entry against the current one to
* see if the entries span a contiguous mapping. If so,
@@ -644,13 +644,12 @@ static void __init pmb_synchronize(void)
*/
if (pmb_can_merge(pmbp, pmbe))
pmbp->link = pmbe;
-
- spin_unlock(&pmbp->lock);
+ raw_spin_unlock(&pmbp->lock);
}
pmbp = pmbe;
- spin_unlock_irqrestore(&pmbe->lock, irqflags);
+ raw_spin_unlock_irqrestore(&pmbe->lock, irqflags);
}
}
@@ -757,7 +756,7 @@ static void __init pmb_resize(void)
/*
* Found it, now resize it.
*/
- spin_lock_irqsave(&pmbe->lock, flags);
+ raw_spin_lock_irqsave(&pmbe->lock, flags);
pmbe->size = SZ_16M;
pmbe->flags &= ~PMB_SZ_MASK;
@@ -767,7 +766,7 @@ static void __init pmb_resize(void)
__set_pmb_entry(pmbe);
- spin_unlock_irqrestore(&pmbe->lock, flags);
+ raw_spin_unlock_irqrestore(&pmbe->lock, flags);
}
read_unlock(&pmb_rwlock);
@@ -866,11 +865,9 @@ static int __init pmb_debugfs_init(void)
struct dentry *dentry;
dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO,
- sh_debugfs_root, NULL, &pmb_debugfs_fops);
+ arch_debugfs_dir, NULL, &pmb_debugfs_fops);
if (!dentry)
return -ENOMEM;
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
return 0;
}
diff --git a/arch/sh/mm/sram.c b/arch/sh/mm/sram.c
new file mode 100644
index 000000000000..bc156ec4545e
--- /dev/null
+++ b/arch/sh/mm/sram.c
@@ -0,0 +1,34 @@
+/*
+ * SRAM pool for tiny memories not otherwise managed.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/sram.h>
+
+/*
+ * This provides a standard SRAM pool for tiny memories that can be
+ * added either by the CPU or the platform code. Typical SRAM sizes
+ * to be inserted in to the pool will generally be less than the page
+ * size, with anything more reasonably sized handled as a NUMA memory
+ * node.
+ */
+struct gen_pool *sram_pool;
+
+static int __init sram_pool_init(void)
+{
+ /*
+ * This is a global pool, we don't care about node locality.
+ */
+ sram_pool = gen_pool_create(1, -1);
+ if (unlikely(!sram_pool))
+ return -ENOMEM;
+
+ return 0;
+}
+core_initcall(sram_pool_init);
diff --git a/arch/sh/mm/tlb-debugfs.c b/arch/sh/mm/tlb-debugfs.c
index 229bf75f28df..dea637a09246 100644
--- a/arch/sh/mm/tlb-debugfs.c
+++ b/arch/sh/mm/tlb-debugfs.c
@@ -151,15 +151,13 @@ static int __init tlb_debugfs_init(void)
{
struct dentry *itlb, *utlb;
- itlb = debugfs_create_file("itlb", S_IRUSR, sh_debugfs_root,
+ itlb = debugfs_create_file("itlb", S_IRUSR, arch_debugfs_dir,
(unsigned int *)TLB_TYPE_ITLB,
&tlb_debugfs_fops);
if (unlikely(!itlb))
return -ENOMEM;
- if (IS_ERR(itlb))
- return PTR_ERR(itlb);
- utlb = debugfs_create_file("utlb", S_IRUSR, sh_debugfs_root,
+ utlb = debugfs_create_file("utlb", S_IRUSR, arch_debugfs_dir,
(unsigned int *)TLB_TYPE_UTLB,
&tlb_debugfs_fops);
if (unlikely(!utlb)) {
@@ -167,11 +165,6 @@ static int __init tlb_debugfs_init(void)
return -ENOMEM;
}
- if (IS_ERR(utlb)) {
- debugfs_remove(itlb);
- return PTR_ERR(utlb);
- }
-
return 0;
}
module_init(tlb_debugfs_init);
diff --git a/arch/sh/mm/tlbflush_32.c b/arch/sh/mm/tlbflush_32.c
index 3fbe03ce8fe3..a6a20d6de4c0 100644
--- a/arch/sh/mm/tlbflush_32.c
+++ b/arch/sh/mm/tlbflush_32.c
@@ -119,3 +119,19 @@ void local_flush_tlb_mm(struct mm_struct *mm)
local_irq_restore(flags);
}
}
+
+void __flush_tlb_global(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ /*
+ * This is the most destructive of the TLB flushing options,
+ * and will tear down all of the UTLB/ITLB mappings, including
+ * wired entries.
+ */
+ __raw_writel(__raw_readl(MMUCR) | MMUCR_TI, MMUCR);
+
+ local_irq_restore(flags);
+}
diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c
index 03db41cc1268..7f5810f5dfdc 100644
--- a/arch/sh/mm/tlbflush_64.c
+++ b/arch/sh/mm/tlbflush_64.c
@@ -455,6 +455,11 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
flush_tlb_all();
}
+void __flush_tlb_global(void)
+{
+ flush_tlb_all();
+}
+
void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
{
}
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index b25aa554ee5e..9f56eb978024 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -52,6 +52,8 @@ MIGOR SH_MIGOR
RSK7201 SH_RSK7201
RSK7203 SH_RSK7203
AP325RXA SH_AP325RXA
+SH2007 SH_SH2007
+SH7757LCR SH_SH7757LCR
SH7763RDP SH_SH7763RDP
SH7785LCR SH_SH7785LCR
SH7785LCR_PT SH_SH7785LCR_PT
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 3e9d31401fb2..8e7bafc5dd0e 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -19,6 +19,7 @@ config SPARC
bool
default y
select OF
+ select OF_PROMTREE
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_ARCH_KGDB if !SMP || SPARC64
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index deeb0fba8029..3c93f08ce187 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -7,7 +7,6 @@ header-y += display7seg.h
header-y += envctrl.h
header-y += fbio.h
header-y += jsflash.h
-header-y += openprom.h
header-y += openpromio.h
header-y += perfctr.h
header-y += psrcompat.h
diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h
index c792830636de..86666f70322e 100644
--- a/arch/sparc/include/asm/floppy_32.h
+++ b/arch/sparc/include/asm/floppy_32.h
@@ -304,7 +304,8 @@ static struct linux_prom_registers fd_regs[2];
static int sun_floppy_init(void)
{
char state[128];
- int tnode, fd_node, num_regs;
+ phandle tnode, fd_node;
+ int num_regs;
struct resource r;
use_virtual_dma = 1;
diff --git a/arch/sparc/include/asm/openprom.h b/arch/sparc/include/asm/openprom.h
index 963e1a45c35f..81cd43432dc0 100644
--- a/arch/sparc/include/asm/openprom.h
+++ b/arch/sparc/include/asm/openprom.h
@@ -11,6 +11,8 @@
#define LINUX_OPPROM_MAGIC 0x10010407
#ifndef __ASSEMBLY__
+#include <linux/of.h>
+
/* V0 prom device operations. */
struct linux_dev_v0_funcs {
int (*v0_devopen)(char *device_str);
@@ -26,7 +28,7 @@ struct linux_dev_v0_funcs {
/* V2 and later prom device operations. */
struct linux_dev_v2_funcs {
- int (*v2_inst2pkg)(int d); /* Convert ihandle to phandle */
+ phandle (*v2_inst2pkg)(int d); /* Convert ihandle to phandle */
char * (*v2_dumb_mem_alloc)(char *va, unsigned sz);
void (*v2_dumb_mem_free)(char *va, unsigned sz);
@@ -168,12 +170,12 @@ struct linux_romvec {
/* Routines for traversing the prom device tree. */
struct linux_nodeops {
- int (*no_nextnode)(int node);
- int (*no_child)(int node);
- int (*no_proplen)(int node, const char *name);
- int (*no_getprop)(int node, const char *name, char *val);
- int (*no_setprop)(int node, const char *name, char *val, int len);
- char * (*no_nextprop)(int node, char *name);
+ phandle (*no_nextnode)(phandle node);
+ phandle (*no_child)(phandle node);
+ int (*no_proplen)(phandle node, const char *name);
+ int (*no_getprop)(phandle node, const char *name, char *val);
+ int (*no_setprop)(phandle node, const char *name, char *val, int len);
+ char * (*no_nextprop)(phandle node, char *name);
};
/* More fun PROM structures for device probing. */
diff --git a/arch/sparc/include/asm/oplib_32.h b/arch/sparc/include/asm/oplib_32.h
index 33e31ce6b31f..51296a6f5005 100644
--- a/arch/sparc/include/asm/oplib_32.h
+++ b/arch/sparc/include/asm/oplib_32.h
@@ -30,7 +30,7 @@ extern unsigned int prom_rev, prom_prev;
/* Root node of the prom device tree, this stays constant after
* initialization is complete.
*/
-extern int prom_root_node;
+extern phandle prom_root_node;
/* Pointer to prom structure containing the device tree traversal
* and usage utility functions. Only prom-lib should use these,
@@ -178,68 +178,68 @@ extern void prom_putsegment(int context, unsigned long virt_addr,
/* PROM device tree traversal functions... */
/* Get the child node of the given node, or zero if no child exists. */
-extern int prom_getchild(int parent_node);
+extern phandle prom_getchild(phandle parent_node);
/* Get the next sibling node of the given node, or zero if no further
* siblings exist.
*/
-extern int prom_getsibling(int node);
+extern phandle prom_getsibling(phandle node);
/* Get the length, at the passed node, of the given property type.
* Returns -1 on error (ie. no such property at this node).
*/
-extern int prom_getproplen(int thisnode, const char *property);
+extern int prom_getproplen(phandle thisnode, const char *property);
/* Fetch the requested property using the given buffer. Returns
* the number of bytes the prom put into your buffer or -1 on error.
*/
-extern int __must_check prom_getproperty(int thisnode, const char *property,
+extern int __must_check prom_getproperty(phandle thisnode, const char *property,
char *prop_buffer, int propbuf_size);
/* Acquire an integer property. */
-extern int prom_getint(int node, char *property);
+extern int prom_getint(phandle node, char *property);
/* Acquire an integer property, with a default value. */
-extern int prom_getintdefault(int node, char *property, int defval);
+extern int prom_getintdefault(phandle node, char *property, int defval);
/* Acquire a boolean property, 0=FALSE 1=TRUE. */
-extern int prom_getbool(int node, char *prop);
+extern int prom_getbool(phandle node, char *prop);
/* Acquire a string property, null string on error. */
-extern void prom_getstring(int node, char *prop, char *buf, int bufsize);
+extern void prom_getstring(phandle node, char *prop, char *buf, int bufsize);
/* Does the passed node have the given "name"? YES=1 NO=0 */
-extern int prom_nodematch(int thisnode, char *name);
+extern int prom_nodematch(phandle thisnode, char *name);
/* Search all siblings starting at the passed node for "name" matching
* the given string. Returns the node on success, zero on failure.
*/
-extern int prom_searchsiblings(int node_start, char *name);
+extern phandle prom_searchsiblings(phandle node_start, char *name);
/* Return the first property type, as a string, for the given node.
* Returns a null string on error.
*/
-extern char *prom_firstprop(int node, char *buffer);
+extern char *prom_firstprop(phandle node, char *buffer);
/* Returns the next property after the passed property for the given
* node. Returns null string on failure.
*/
-extern char *prom_nextprop(int node, char *prev_property, char *buffer);
+extern char *prom_nextprop(phandle node, char *prev_property, char *buffer);
/* Returns phandle of the path specified */
-extern int prom_finddevice(char *name);
+extern phandle prom_finddevice(char *name);
/* Returns 1 if the specified node has given property. */
-extern int prom_node_has_property(int node, char *property);
+extern int prom_node_has_property(phandle node, char *property);
/* Set the indicated property at the given node with the passed value.
* Returns the number of bytes of your value that the prom took.
*/
-extern int prom_setprop(int node, const char *prop_name, char *prop_value,
+extern int prom_setprop(phandle node, const char *prop_name, char *prop_value,
int value_size);
-extern int prom_pathtoinode(char *path);
-extern int prom_inst2pkg(int);
+extern phandle prom_pathtoinode(char *path);
+extern phandle prom_inst2pkg(int);
/* Dorking with Bus ranges... */
@@ -247,13 +247,13 @@ extern int prom_inst2pkg(int);
extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs);
/* Apply ranges of any prom node (and optionally parent node as well) to registers. */
-extern void prom_apply_generic_ranges(int node, int parent,
+extern void prom_apply_generic_ranges(phandle node, phandle parent,
struct linux_prom_registers *sbusregs, int nregs);
/* CPU probing helpers. */
-int cpu_find_by_instance(int instance, int *prom_node, int *mid);
-int cpu_find_by_mid(int mid, int *prom_node);
-int cpu_get_hwmid(int prom_node);
+int cpu_find_by_instance(int instance, phandle *prom_node, int *mid);
+int cpu_find_by_mid(int mid, phandle *prom_node);
+int cpu_get_hwmid(phandle prom_node);
extern spinlock_t prom_lock;
diff --git a/arch/sparc/include/asm/oplib_64.h b/arch/sparc/include/asm/oplib_64.h
index 3e0b2d62303d..c9cc078e3e31 100644
--- a/arch/sparc/include/asm/oplib_64.h
+++ b/arch/sparc/include/asm/oplib_64.h
@@ -16,7 +16,7 @@ extern char prom_version[];
/* Root node of the prom device tree, this stays constant after
* initialization is complete.
*/
-extern int prom_root_node;
+extern phandle prom_root_node;
/* PROM stdin and stdout */
extern int prom_stdin, prom_stdout;
@@ -24,7 +24,7 @@ extern int prom_stdin, prom_stdout;
/* /chosen node of the prom device tree, this stays constant after
* initialization is complete.
*/
-extern int prom_chosen_node;
+extern phandle prom_chosen_node;
/* Helper values and strings in arch/sparc64/kernel/head.S */
extern const char prom_peer_name[];
@@ -218,68 +218,69 @@ extern void prom_unmap(unsigned long size, unsigned long vaddr);
/* PROM device tree traversal functions... */
/* Get the child node of the given node, or zero if no child exists. */
-extern int prom_getchild(int parent_node);
+extern phandle prom_getchild(phandle parent_node);
/* Get the next sibling node of the given node, or zero if no further
* siblings exist.
*/
-extern int prom_getsibling(int node);
+extern phandle prom_getsibling(phandle node);
/* Get the length, at the passed node, of the given property type.
* Returns -1 on error (ie. no such property at this node).
*/
-extern int prom_getproplen(int thisnode, const char *property);
+extern int prom_getproplen(phandle thisnode, const char *property);
/* Fetch the requested property using the given buffer. Returns
* the number of bytes the prom put into your buffer or -1 on error.
*/
-extern int prom_getproperty(int thisnode, const char *property,
+extern int prom_getproperty(phandle thisnode, const char *property,
char *prop_buffer, int propbuf_size);
/* Acquire an integer property. */
-extern int prom_getint(int node, const char *property);
+extern int prom_getint(phandle node, const char *property);
/* Acquire an integer property, with a default value. */
-extern int prom_getintdefault(int node, const char *property, int defval);
+extern int prom_getintdefault(phandle node, const char *property, int defval);
/* Acquire a boolean property, 0=FALSE 1=TRUE. */
-extern int prom_getbool(int node, const char *prop);
+extern int prom_getbool(phandle node, const char *prop);
/* Acquire a string property, null string on error. */
-extern void prom_getstring(int node, const char *prop, char *buf, int bufsize);
+extern void prom_getstring(phandle node, const char *prop, char *buf,
+ int bufsize);
/* Does the passed node have the given "name"? YES=1 NO=0 */
-extern int prom_nodematch(int thisnode, const char *name);
+extern int prom_nodematch(phandle thisnode, const char *name);
/* Search all siblings starting at the passed node for "name" matching
* the given string. Returns the node on success, zero on failure.
*/
-extern int prom_searchsiblings(int node_start, const char *name);
+extern phandle prom_searchsiblings(phandle node_start, const char *name);
/* Return the first property type, as a string, for the given node.
* Returns a null string on error. Buffer should be at least 32B long.
*/
-extern char *prom_firstprop(int node, char *buffer);
+extern char *prom_firstprop(phandle node, char *buffer);
/* Returns the next property after the passed property for the given
* node. Returns null string on failure. Buffer should be at least 32B long.
*/
-extern char *prom_nextprop(int node, const char *prev_property, char *buffer);
+extern char *prom_nextprop(phandle node, const char *prev_property, char *buf);
/* Returns 1 if the specified node has given property. */
-extern int prom_node_has_property(int node, const char *property);
+extern int prom_node_has_property(phandle node, const char *property);
/* Returns phandle of the path specified */
-extern int prom_finddevice(const char *name);
+extern phandle prom_finddevice(const char *name);
/* Set the indicated property at the given node with the passed value.
* Returns the number of bytes of your value that the prom took.
*/
-extern int prom_setprop(int node, const char *prop_name, char *prop_value,
+extern int prom_setprop(phandle node, const char *prop_name, char *prop_value,
int value_size);
-extern int prom_pathtoinode(const char *path);
-extern int prom_inst2pkg(int);
+extern phandle prom_pathtoinode(const char *path);
+extern phandle prom_inst2pkg(int);
extern int prom_service_exists(const char *service_name);
extern void prom_sun4v_guest_soft_state(void);
diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index 291f12575edd..56bbaadef646 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -18,6 +18,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/types.h>
+#include <linux/of_pdt.h>
#include <linux/proc_fs.h>
#include <linux/mutex.h>
#include <asm/atomic.h>
@@ -67,8 +68,8 @@ extern struct device_node *of_console_device;
extern char *of_console_path;
extern char *of_console_options;
-extern void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp);
-extern char *build_full_name(struct device_node *dp);
+extern void irq_trans_init(struct device_node *dp);
+extern char *build_path_component(struct device_node *dp);
#endif /* __KERNEL__ */
#endif /* _SPARC_PROM_H */
diff --git a/arch/sparc/kernel/auxio_32.c b/arch/sparc/kernel/auxio_32.c
index ee8d214cae1e..35f48837871a 100644
--- a/arch/sparc/kernel/auxio_32.c
+++ b/arch/sparc/kernel/auxio_32.c
@@ -23,7 +23,7 @@ static DEFINE_SPINLOCK(auxio_lock);
void __init auxio_probe(void)
{
- int node, auxio_nd;
+ phandle node, auxio_nd;
struct linux_prom_registers auxregs[1];
struct resource r;
@@ -113,7 +113,7 @@ volatile unsigned char * auxio_power_register = NULL;
void __init auxio_power_probe(void)
{
struct linux_prom_registers regs;
- int node;
+ phandle node;
struct resource r;
/* Attempt to find the sun4m power control node. */
diff --git a/arch/sparc/kernel/btext.c b/arch/sparc/kernel/btext.c
index 8cc2d56ffe9a..89aa4eb20cf5 100644
--- a/arch/sparc/kernel/btext.c
+++ b/arch/sparc/kernel/btext.c
@@ -40,7 +40,7 @@ static unsigned char *dispDeviceBase __force_data;
static unsigned char vga_font[cmapsz];
-static int __init btext_initialize(unsigned int node)
+static int __init btext_initialize(phandle node)
{
unsigned int width, height, depth, pitch;
unsigned long address = 0;
@@ -309,7 +309,7 @@ static struct console btext_console = {
int __init btext_find_display(void)
{
- unsigned int node;
+ phandle node;
char type[32];
int ret;
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index 62dc7a021413..d2eddd6647cd 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -31,9 +31,9 @@ static char *cpu_mid_prop(void)
return "mid";
}
-static int check_cpu_node(int nd, int *cur_inst,
- int (*compare)(int, int, void *), void *compare_arg,
- int *prom_node, int *mid)
+static int check_cpu_node(phandle nd, int *cur_inst,
+ int (*compare)(phandle, int, void *), void *compare_arg,
+ phandle *prom_node, int *mid)
{
if (!compare(nd, *cur_inst, compare_arg)) {
if (prom_node)
@@ -51,8 +51,8 @@ static int check_cpu_node(int nd, int *cur_inst,
return -ENODEV;
}
-static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
- int *prom_node, int *mid)
+static int __cpu_find_by(int (*compare)(phandle, int, void *),
+ void *compare_arg, phandle *prom_node, int *mid)
{
struct device_node *dp;
int cur_inst;
@@ -71,7 +71,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
return -ENODEV;
}
-static int cpu_instance_compare(int nd, int instance, void *_arg)
+static int cpu_instance_compare(phandle nd, int instance, void *_arg)
{
int desired_instance = (int) _arg;
@@ -80,13 +80,13 @@ static int cpu_instance_compare(int nd, int instance, void *_arg)
return -ENODEV;
}
-int cpu_find_by_instance(int instance, int *prom_node, int *mid)
+int cpu_find_by_instance(int instance, phandle *prom_node, int *mid)
{
return __cpu_find_by(cpu_instance_compare, (void *)instance,
prom_node, mid);
}
-static int cpu_mid_compare(int nd, int instance, void *_arg)
+static int cpu_mid_compare(phandle nd, int instance, void *_arg)
{
int desired_mid = (int) _arg;
int this_mid;
@@ -98,7 +98,7 @@ static int cpu_mid_compare(int nd, int instance, void *_arg)
return -ENODEV;
}
-int cpu_find_by_mid(int mid, int *prom_node)
+int cpu_find_by_mid(int mid, phandle *prom_node)
{
return __cpu_find_by(cpu_mid_compare, (void *)mid,
prom_node, NULL);
@@ -108,7 +108,7 @@ int cpu_find_by_mid(int mid, int *prom_node)
* address (0-3). This gives us the true hardware mid, which might have
* some other bits set. On 4d hardware and software mids are the same.
*/
-int cpu_get_hwmid(int prom_node)
+int cpu_get_hwmid(phandle prom_node)
{
return prom_getintdefault(prom_node, cpu_mid_prop(), -ENODEV);
}
@@ -119,7 +119,8 @@ void __init device_scan(void)
#ifndef CONFIG_SMP
{
- int err, cpu_node;
+ phandle cpu_node;
+ int err;
err = cpu_find_by_instance(0, &cpu_node, NULL);
if (err) {
/* Probably a sun4e, Sun is trying to trick us ;-) */
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c
index 6a7b4dbc8e09..2d51527d810f 100644
--- a/arch/sparc/kernel/leon_kernel.c
+++ b/arch/sparc/kernel/leon_kernel.c
@@ -282,5 +282,5 @@ void __init leon_init_IRQ(void)
void __init leon_init(void)
{
- prom_build_more = &leon_node_init;
+ of_pdt_build_more = &leon_node_init;
}
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index d36a8d391ca0..aeaa09a3c655 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -284,7 +284,7 @@ int __init pcic_probe(void)
struct linux_prom_registers regs[PROMREG_MAX];
struct linux_pbm_info* pbm;
char namebuf[64];
- int node;
+ phandle node;
int err;
if (pcic0_up) {
@@ -440,7 +440,7 @@ static int __devinit pdev_to_pnode(struct linux_pbm_info *pbm,
{
struct linux_prom_pci_registers regs[PROMREG_MAX];
int err;
- int node = prom_getchild(pbm->prom_node);
+ phandle node = prom_getchild(pbm->prom_node);
while(node) {
err = prom_getproperty(node, "reg",
diff --git a/arch/sparc/kernel/prom.h b/arch/sparc/kernel/prom.h
index eeb04a782ec8..cf5fe1c0b024 100644
--- a/arch/sparc/kernel/prom.h
+++ b/arch/sparc/kernel/prom.h
@@ -4,12 +4,6 @@
#include <linux/spinlock.h>
#include <asm/prom.h>
-extern void * prom_early_alloc(unsigned long size);
-extern void irq_trans_init(struct device_node *dp);
-
-extern unsigned int prom_unique_id;
-
-extern char *build_path_component(struct device_node *dp);
extern void of_console_init(void);
extern unsigned int prom_early_allocated;
diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c
index 1f830da2ddf2..ed25834328f4 100644
--- a/arch/sparc/kernel/prom_common.c
+++ b/arch/sparc/kernel/prom_common.c
@@ -20,14 +20,13 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/of.h>
+#include <linux/of_pdt.h>
#include <asm/prom.h>
#include <asm/oplib.h>
#include <asm/leon.h>
#include "prom.h"
-void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp);
-
struct device_node *of_console_device;
EXPORT_SYMBOL(of_console_device);
@@ -119,192 +118,47 @@ int of_find_in_proplist(const char *list, const char *match, int len)
}
EXPORT_SYMBOL(of_find_in_proplist);
-unsigned int prom_unique_id;
-
-static struct property * __init build_one_prop(phandle node, char *prev,
- char *special_name,
- void *special_val,
- int special_len)
+/*
+ * SPARC32 and SPARC64's prom_nextprop() do things differently
+ * here, despite sharing the same interface. SPARC32 doesn't fill in 'buf',
+ * returning NULL on an error. SPARC64 fills in 'buf', but sets it to an
+ * empty string upon error.
+ */
+static int __init handle_nextprop_quirks(char *buf, const char *name)
{
- static struct property *tmp = NULL;
- struct property *p;
- const char *name;
-
- if (tmp) {
- p = tmp;
- memset(p, 0, sizeof(*p) + 32);
- tmp = NULL;
- } else {
- p = prom_early_alloc(sizeof(struct property) + 32);
- p->unique_id = prom_unique_id++;
- }
-
- p->name = (char *) (p + 1);
- if (special_name) {
- strcpy(p->name, special_name);
- p->length = special_len;
- p->value = prom_early_alloc(special_len);
- memcpy(p->value, special_val, special_len);
- } else {
- if (prev == NULL) {
- name = prom_firstprop(node, p->name);
- } else {
- name = prom_nextprop(node, prev, p->name);
- }
+ if (!name || strlen(name) == 0)
+ return -1;
- if (!name || strlen(name) == 0) {
- tmp = p;
- return NULL;
- }
#ifdef CONFIG_SPARC32
- strcpy(p->name, name);
+ strcpy(buf, name);
#endif
- p->length = prom_getproplen(node, p->name);
- if (p->length <= 0) {
- p->length = 0;
- } else {
- int len;
-
- p->value = prom_early_alloc(p->length + 1);
- len = prom_getproperty(node, p->name, p->value,
- p->length);
- if (len <= 0)
- p->length = 0;
- ((unsigned char *)p->value)[p->length] = '\0';
- }
- }
- return p;
-}
-
-static struct property * __init build_prop_list(phandle node)
-{
- struct property *head, *tail;
-
- head = tail = build_one_prop(node, NULL,
- ".node", &node, sizeof(node));
-
- tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
- tail = tail->next;
- while(tail) {
- tail->next = build_one_prop(node, tail->name,
- NULL, NULL, 0);
- tail = tail->next;
- }
-
- return head;
-}
-
-static char * __init get_one_property(phandle node, const char *name)
-{
- char *buf = "<NULL>";
- int len;
-
- len = prom_getproplen(node, name);
- if (len > 0) {
- buf = prom_early_alloc(len);
- len = prom_getproperty(node, name, buf, len);
- }
-
- return buf;
-}
-
-static struct device_node * __init prom_create_node(phandle node,
- struct device_node *parent)
-{
- struct device_node *dp;
-
- if (!node)
- return NULL;
-
- dp = prom_early_alloc(sizeof(*dp));
- dp->unique_id = prom_unique_id++;
- dp->parent = parent;
-
- kref_init(&dp->kref);
-
- dp->name = get_one_property(node, "name");
- dp->type = get_one_property(node, "device_type");
- dp->phandle = node;
-
- dp->properties = build_prop_list(node);
-
- irq_trans_init(dp);
-
- return dp;
-}
-
-char * __init build_full_name(struct device_node *dp)
-{
- int len, ourlen, plen;
- char *n;
-
- plen = strlen(dp->parent->full_name);
- ourlen = strlen(dp->path_component_name);
- len = ourlen + plen + 2;
-
- n = prom_early_alloc(len);
- strcpy(n, dp->parent->full_name);
- if (!of_node_is_root(dp->parent)) {
- strcpy(n + plen, "/");
- plen++;
- }
- strcpy(n + plen, dp->path_component_name);
-
- return n;
+ return 0;
}
-static struct device_node * __init prom_build_tree(struct device_node *parent,
- phandle node,
- struct device_node ***nextp)
+static int __init prom_common_nextprop(phandle node, char *prev, char *buf)
{
- struct device_node *ret = NULL, *prev_sibling = NULL;
- struct device_node *dp;
-
- while (1) {
- dp = prom_create_node(node, parent);
- if (!dp)
- break;
-
- if (prev_sibling)
- prev_sibling->sibling = dp;
-
- if (!ret)
- ret = dp;
- prev_sibling = dp;
-
- *(*nextp) = dp;
- *nextp = &dp->allnext;
-
- dp->path_component_name = build_path_component(dp);
- dp->full_name = build_full_name(dp);
-
- dp->child = prom_build_tree(dp, prom_getchild(node), nextp);
-
- if (prom_build_more)
- prom_build_more(dp, nextp);
-
- node = prom_getsibling(node);
- }
+ const char *name;
- return ret;
+ buf[0] = '\0';
+ name = prom_nextprop(node, prev, buf);
+ return handle_nextprop_quirks(buf, name);
}
unsigned int prom_early_allocated __initdata;
+static struct of_pdt_ops prom_sparc_ops __initdata = {
+ .nextprop = prom_common_nextprop,
+ .getproplen = prom_getproplen,
+ .getproperty = prom_getproperty,
+ .getchild = prom_getchild,
+ .getsibling = prom_getsibling,
+};
+
void __init prom_build_devicetree(void)
{
- struct device_node **nextp;
-
- allnodes = prom_create_node(prom_root_node, NULL);
- allnodes->path_component_name = "";
- allnodes->full_name = "/";
-
- nextp = &allnodes->allnext;
- allnodes->child = prom_build_tree(allnodes,
- prom_getchild(allnodes->phandle),
- &nextp);
+ of_pdt_build_devicetree(prom_root_node, &prom_sparc_ops);
of_console_init();
- printk("PROM: Built device tree with %u bytes of memory.\n",
- prom_early_allocated);
+ pr_info("PROM: Built device tree with %u bytes of memory.\n",
+ prom_early_allocated);
}
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 5f72de67588b..29bafe051bb1 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -315,7 +315,7 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_IP_PNP
if (!ic_set_manually) {
- int chosen = prom_finddevice ("/chosen");
+ phandle chosen = prom_finddevice("/chosen");
u32 cl, sv, gw;
cl = prom_getintdefault (chosen, "client-ip", 0);
diff --git a/arch/sparc/kernel/starfire.c b/arch/sparc/kernel/starfire.c
index 060d0f3a6151..a4446c0fb7a1 100644
--- a/arch/sparc/kernel/starfire.c
+++ b/arch/sparc/kernel/starfire.c
@@ -23,7 +23,7 @@ int this_is_starfire = 0;
void check_if_starfire(void)
{
- int ssnode = prom_finddevice("/ssp-serial");
+ phandle ssnode = prom_finddevice("/ssp-serial");
if (ssnode != 0 && ssnode != -1)
this_is_starfire = 1;
}
diff --git a/arch/sparc/kernel/tadpole.c b/arch/sparc/kernel/tadpole.c
index f476a5f4af6a..9aba8bd5a78b 100644
--- a/arch/sparc/kernel/tadpole.c
+++ b/arch/sparc/kernel/tadpole.c
@@ -100,7 +100,7 @@ static void swift_clockstop(void)
void __init clock_stop_probe(void)
{
- unsigned int node, clk_nd;
+ phandle node, clk_nd;
char name[20];
prom_getstring(prom_root_node, "name", name, sizeof(name));
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 4c2572773b55..2f6ae1d1fb6b 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -88,7 +88,7 @@ static void __init read_obp_memory(const char *property,
struct linux_prom64_registers *regs,
int *num_ents)
{
- int node = prom_finddevice("/memory");
+ phandle node = prom_finddevice("/memory");
int prop_size = prom_getproplen(node, property);
int ents, ret, i;
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index b0b43aa5e45a..92319aa8b662 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1262,7 +1262,8 @@ extern unsigned long bootmem_init(unsigned long *pages_avail);
void __init srmmu_paging_init(void)
{
- int i, cpunode;
+ int i;
+ phandle cpunode;
char node_str[128];
pgd_t *pgd;
pmd_t *pmd;
@@ -1398,7 +1399,8 @@ static void __init srmmu_is_bad(void)
static void __init init_vac_layout(void)
{
- int nd, cache_lines;
+ phandle nd;
+ int cache_lines;
char node_str[128];
#ifdef CONFIG_SMP
int cpu = 0;
@@ -2082,7 +2084,7 @@ static void __init get_srmmu_type(void)
/* Next check for Fujitsu Swift. */
if(psr_typ == 0 && psr_vers == 4) {
- int cpunode;
+ phandle cpunode;
char node_str[128];
/* Look if it is not a TurboSparc emulating Swift... */
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index 4289f90f8697..ddd0d86e508e 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -420,7 +420,7 @@ volatile unsigned long __iomem *sun4c_memerr_reg = NULL;
void __init sun4c_probe_memerr_reg(void)
{
- int node;
+ phandle node;
struct linux_prom_registers regs[1];
node = prom_getchild(prom_root_node);
diff --git a/arch/sparc/prom/init_32.c b/arch/sparc/prom/init_32.c
index ccb36c7f9b8c..d342dba4dd54 100644
--- a/arch/sparc/prom/init_32.c
+++ b/arch/sparc/prom/init_32.c
@@ -20,7 +20,7 @@ enum prom_major_version prom_vers;
unsigned int prom_rev, prom_prev;
/* The root node of the prom device tree. */
-int prom_root_node;
+phandle prom_root_node;
EXPORT_SYMBOL(prom_root_node);
/* Pointer to the device tree operations structure. */
diff --git a/arch/sparc/prom/init_64.c b/arch/sparc/prom/init_64.c
index 7b00f89490a4..3ff911e7d25b 100644
--- a/arch/sparc/prom/init_64.c
+++ b/arch/sparc/prom/init_64.c
@@ -19,7 +19,7 @@ char prom_version[80];
/* The root node of the prom device tree. */
int prom_stdin, prom_stdout;
-int prom_chosen_node;
+phandle prom_chosen_node;
/* You must call prom_init() before you attempt to use any of the
* routines in the prom library. It returns 0 on success, 1 on
@@ -30,7 +30,7 @@ extern void prom_cif_init(void *, void *);
void __init prom_init(void *cif_handler, void *cif_stack)
{
- int node;
+ phandle node;
prom_cif_init(cif_handler, cif_stack);
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
index fac7899a29c3..3f263a64857d 100644
--- a/arch/sparc/prom/memory.c
+++ b/arch/sparc/prom/memory.c
@@ -31,7 +31,8 @@ static int __init prom_meminit_v0(void)
static int __init prom_meminit_v2(void)
{
struct linux_prom_registers reg[64];
- int node, size, num_ents, i;
+ phandle node;
+ int size, num_ents, i;
node = prom_searchsiblings(prom_getchild(prom_root_node), "memory");
size = prom_getproperty(node, "available", (char *) reg, sizeof(reg));
diff --git a/arch/sparc/prom/misc_64.c b/arch/sparc/prom/misc_64.c
index 6cb1581d6aef..d24bc44e361e 100644
--- a/arch/sparc/prom/misc_64.c
+++ b/arch/sparc/prom/misc_64.c
@@ -183,7 +183,8 @@ unsigned char prom_get_idprom(char *idbuf, int num_bytes)
int prom_get_mmu_ihandle(void)
{
- int node, ret;
+ phandle node;
+ int ret;
if (prom_mmu_ihandle_cache != 0)
return prom_mmu_ihandle_cache;
@@ -201,7 +202,8 @@ int prom_get_mmu_ihandle(void)
static int prom_get_memory_ihandle(void)
{
static int memory_ihandle_cache;
- int node, ret;
+ phandle node;
+ int ret;
if (memory_ihandle_cache != 0)
return memory_ihandle_cache;
diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c
index aeff43e44e45..541fc829c207 100644
--- a/arch/sparc/prom/ranges.c
+++ b/arch/sparc/prom/ranges.c
@@ -68,7 +68,7 @@ EXPORT_SYMBOL(prom_apply_obio_ranges);
void __init prom_ranges_init(void)
{
- int node, obio_node;
+ phandle node, obio_node;
int success;
num_obio_ranges = 0;
@@ -89,8 +89,8 @@ void __init prom_ranges_init(void)
prom_printf("PROMLIB: obio_ranges %d\n", num_obio_ranges);
}
-void
-prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
+void prom_apply_generic_ranges(phandle node, phandle parent,
+ struct linux_prom_registers *regs, int nregs)
{
int success;
int num_ranges;
diff --git a/arch/sparc/prom/tree_32.c b/arch/sparc/prom/tree_32.c
index b21592f8e3fe..63e08e149774 100644
--- a/arch/sparc/prom/tree_32.c
+++ b/arch/sparc/prom/tree_32.c
@@ -20,10 +20,10 @@ extern void restore_current(void);
static char promlib_buf[128];
/* Internal version of prom_getchild that does not alter return values. */
-int __prom_getchild(int node)
+phandle __prom_getchild(phandle node)
{
unsigned long flags;
- int cnode;
+ phandle cnode;
spin_lock_irqsave(&prom_lock, flags);
cnode = prom_nodeops->no_child(node);
@@ -36,9 +36,9 @@ int __prom_getchild(int node)
/* Return the child of node 'node' or zero if no this node has no
* direct descendent.
*/
-int prom_getchild(int node)
+phandle prom_getchild(phandle node)
{
- int cnode;
+ phandle cnode;
if (node == -1)
return 0;
@@ -52,10 +52,10 @@ int prom_getchild(int node)
EXPORT_SYMBOL(prom_getchild);
/* Internal version of prom_getsibling that does not alter return values. */
-int __prom_getsibling(int node)
+phandle __prom_getsibling(phandle node)
{
unsigned long flags;
- int cnode;
+ phandle cnode;
spin_lock_irqsave(&prom_lock, flags);
cnode = prom_nodeops->no_nextnode(node);
@@ -68,9 +68,9 @@ int __prom_getsibling(int node)
/* Return the next sibling of node 'node' or zero if no more siblings
* at this level of depth in the tree.
*/
-int prom_getsibling(int node)
+phandle prom_getsibling(phandle node)
{
- int sibnode;
+ phandle sibnode;
if (node == -1)
return 0;
@@ -86,7 +86,7 @@ EXPORT_SYMBOL(prom_getsibling);
/* Return the length in bytes of property 'prop' at node 'node'.
* Return -1 on error.
*/
-int prom_getproplen(int node, const char *prop)
+int prom_getproplen(phandle node, const char *prop)
{
int ret;
unsigned long flags;
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(prom_getproplen);
* 'buffer' which has a size of 'bufsize'. If the acquisition
* was successful the length will be returned, else -1 is returned.
*/
-int prom_getproperty(int node, const char *prop, char *buffer, int bufsize)
+int prom_getproperty(phandle node, const char *prop, char *buffer, int bufsize)
{
int plen, ret;
unsigned long flags;
@@ -126,7 +126,7 @@ EXPORT_SYMBOL(prom_getproperty);
/* Acquire an integer property and return its value. Returns -1
* on failure.
*/
-int prom_getint(int node, char *prop)
+int prom_getint(phandle node, char *prop)
{
static int intprop;
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(prom_getint);
/* Acquire an integer property, upon error return the passed default
* integer.
*/
-int prom_getintdefault(int node, char *property, int deflt)
+int prom_getintdefault(phandle node, char *property, int deflt)
{
int retval;
@@ -152,7 +152,7 @@ int prom_getintdefault(int node, char *property, int deflt)
EXPORT_SYMBOL(prom_getintdefault);
/* Acquire a boolean property, 1=TRUE 0=FALSE. */
-int prom_getbool(int node, char *prop)
+int prom_getbool(phandle node, char *prop)
{
int retval;
@@ -166,7 +166,7 @@ EXPORT_SYMBOL(prom_getbool);
* string on error. The char pointer is the user supplied string
* buffer.
*/
-void prom_getstring(int node, char *prop, char *user_buf, int ubuf_size)
+void prom_getstring(phandle node, char *prop, char *user_buf, int ubuf_size)
{
int len;
@@ -180,7 +180,7 @@ EXPORT_SYMBOL(prom_getstring);
/* Does the device at node 'node' have name 'name'?
* YES = 1 NO = 0
*/
-int prom_nodematch(int node, char *name)
+int prom_nodematch(phandle node, char *name)
{
int error;
@@ -194,10 +194,11 @@ int prom_nodematch(int node, char *name)
/* Search siblings at 'node_start' for a node with name
* 'nodename'. Return node if successful, zero if not.
*/
-int prom_searchsiblings(int node_start, char *nodename)
+phandle prom_searchsiblings(phandle node_start, char *nodename)
{
- int thisnode, error;
+ phandle thisnode;
+ int error;
for(thisnode = node_start; thisnode;
thisnode=prom_getsibling(thisnode)) {
@@ -213,7 +214,7 @@ int prom_searchsiblings(int node_start, char *nodename)
EXPORT_SYMBOL(prom_searchsiblings);
/* Interal version of nextprop that does not alter return values. */
-char * __prom_nextprop(int node, char * oprop)
+char *__prom_nextprop(phandle node, char * oprop)
{
unsigned long flags;
char *prop;
@@ -228,7 +229,7 @@ char * __prom_nextprop(int node, char * oprop)
/* Return the first property name for node 'node'. */
/* buffer is unused argument, but as v9 uses it, we need to have the same interface */
-char * prom_firstprop(int node, char *bufer)
+char *prom_firstprop(phandle node, char *bufer)
{
if (node == 0 || node == -1)
return "";
@@ -241,7 +242,7 @@ EXPORT_SYMBOL(prom_firstprop);
* at node 'node' . Returns empty string if no more
* property types for this node.
*/
-char * prom_nextprop(int node, char *oprop, char *buffer)
+char *prom_nextprop(phandle node, char *oprop, char *buffer)
{
if (node == 0 || node == -1)
return "";
@@ -250,11 +251,11 @@ char * prom_nextprop(int node, char *oprop, char *buffer)
}
EXPORT_SYMBOL(prom_nextprop);
-int prom_finddevice(char *name)
+phandle prom_finddevice(char *name)
{
char nbuf[128];
char *s = name, *d;
- int node = prom_root_node, node2;
+ phandle node = prom_root_node, node2;
unsigned int which_io, phys_addr;
struct linux_prom_registers reg[PROMREG_MAX];
@@ -298,7 +299,7 @@ int prom_finddevice(char *name)
}
EXPORT_SYMBOL(prom_finddevice);
-int prom_node_has_property(int node, char *prop)
+int prom_node_has_property(phandle node, char *prop)
{
char *current_property = "";
@@ -314,7 +315,7 @@ EXPORT_SYMBOL(prom_node_has_property);
/* Set property 'pname' at node 'node' to value 'value' which has a length
* of 'size' bytes. Return the number of bytes the prom accepted.
*/
-int prom_setprop(int node, const char *pname, char *value, int size)
+int prom_setprop(phandle node, const char *pname, char *value, int size)
{
unsigned long flags;
int ret;
@@ -329,9 +330,9 @@ int prom_setprop(int node, const char *pname, char *value, int size)
}
EXPORT_SYMBOL(prom_setprop);
-int prom_inst2pkg(int inst)
+phandle prom_inst2pkg(int inst)
{
- int node;
+ phandle node;
unsigned long flags;
spin_lock_irqsave(&prom_lock, flags);
@@ -345,9 +346,10 @@ int prom_inst2pkg(int inst)
/* Return 'node' assigned to a particular prom 'path'
* FIXME: Should work for v0 as well
*/
-int prom_pathtoinode(char *path)
+phandle prom_pathtoinode(char *path)
{
- int node, inst;
+ phandle node;
+ int inst;
inst = prom_devopen (path);
if (inst == -1) return 0;
diff --git a/arch/sparc/prom/tree_64.c b/arch/sparc/prom/tree_64.c
index 9d3f9137a43a..691be68932f8 100644
--- a/arch/sparc/prom/tree_64.c
+++ b/arch/sparc/prom/tree_64.c
@@ -16,7 +16,7 @@
#include <asm/oplib.h>
#include <asm/ldc.h>
-static int prom_node_to_node(const char *type, int node)
+static phandle prom_node_to_node(const char *type, phandle node)
{
unsigned long args[5];
@@ -28,20 +28,20 @@ static int prom_node_to_node(const char *type, int node)
p1275_cmd_direct(args);
- return (int) args[4];
+ return (phandle) args[4];
}
/* Return the child of node 'node' or zero if no this node has no
* direct descendent.
*/
-inline int __prom_getchild(int node)
+inline phandle __prom_getchild(phandle node)
{
return prom_node_to_node("child", node);
}
-inline int prom_getchild(int node)
+inline phandle prom_getchild(phandle node)
{
- int cnode;
+ phandle cnode;
if (node == -1)
return 0;
@@ -52,9 +52,9 @@ inline int prom_getchild(int node)
}
EXPORT_SYMBOL(prom_getchild);
-inline int prom_getparent(int node)
+inline phandle prom_getparent(phandle node)
{
- int cnode;
+ phandle cnode;
if (node == -1)
return 0;
@@ -67,14 +67,14 @@ inline int prom_getparent(int node)
/* Return the next sibling of node 'node' or zero if no more siblings
* at this level of depth in the tree.
*/
-inline int __prom_getsibling(int node)
+inline phandle __prom_getsibling(phandle node)
{
return prom_node_to_node(prom_peer_name, node);
}
-inline int prom_getsibling(int node)
+inline phandle prom_getsibling(phandle node)
{
- int sibnode;
+ phandle sibnode;
if (node == -1)
return 0;
@@ -89,7 +89,7 @@ EXPORT_SYMBOL(prom_getsibling);
/* Return the length in bytes of property 'prop' at node 'node'.
* Return -1 on error.
*/
-inline int prom_getproplen(int node, const char *prop)
+inline int prom_getproplen(phandle node, const char *prop)
{
unsigned long args[6];
@@ -113,7 +113,7 @@ EXPORT_SYMBOL(prom_getproplen);
* 'buffer' which has a size of 'bufsize'. If the acquisition
* was successful the length will be returned, else -1 is returned.
*/
-inline int prom_getproperty(int node, const char *prop,
+inline int prom_getproperty(phandle node, const char *prop,
char *buffer, int bufsize)
{
unsigned long args[8];
@@ -141,7 +141,7 @@ EXPORT_SYMBOL(prom_getproperty);
/* Acquire an integer property and return its value. Returns -1
* on failure.
*/
-inline int prom_getint(int node, const char *prop)
+inline int prom_getint(phandle node, const char *prop)
{
int intprop;
@@ -156,7 +156,7 @@ EXPORT_SYMBOL(prom_getint);
* integer.
*/
-int prom_getintdefault(int node, const char *property, int deflt)
+int prom_getintdefault(phandle node, const char *property, int deflt)
{
int retval;
@@ -169,7 +169,7 @@ int prom_getintdefault(int node, const char *property, int deflt)
EXPORT_SYMBOL(prom_getintdefault);
/* Acquire a boolean property, 1=TRUE 0=FALSE. */
-int prom_getbool(int node, const char *prop)
+int prom_getbool(phandle node, const char *prop)
{
int retval;
@@ -184,7 +184,8 @@ EXPORT_SYMBOL(prom_getbool);
* string on error. The char pointer is the user supplied string
* buffer.
*/
-void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size)
+void prom_getstring(phandle node, const char *prop, char *user_buf,
+ int ubuf_size)
{
int len;
@@ -198,7 +199,7 @@ EXPORT_SYMBOL(prom_getstring);
/* Does the device at node 'node' have name 'name'?
* YES = 1 NO = 0
*/
-int prom_nodematch(int node, const char *name)
+int prom_nodematch(phandle node, const char *name)
{
char namebuf[128];
prom_getproperty(node, "name", namebuf, sizeof(namebuf));
@@ -210,10 +211,10 @@ int prom_nodematch(int node, const char *name)
/* Search siblings at 'node_start' for a node with name
* 'nodename'. Return node if successful, zero if not.
*/
-int prom_searchsiblings(int node_start, const char *nodename)
+phandle prom_searchsiblings(phandle node_start, const char *nodename)
{
-
- int thisnode, error;
+ phandle thisnode;
+ int error;
char promlib_buf[128];
for(thisnode = node_start; thisnode;
@@ -234,7 +235,7 @@ static const char *prom_nextprop_name = "nextprop";
/* Return the first property type for node 'node'.
* buffer should be at least 32B in length
*/
-inline char *prom_firstprop(int node, char *buffer)
+inline char *prom_firstprop(phandle node, char *buffer)
{
unsigned long args[7];
@@ -260,7 +261,7 @@ EXPORT_SYMBOL(prom_firstprop);
* at node 'node' . Returns NULL string if no more
* property types for this node.
*/
-inline char *prom_nextprop(int node, const char *oprop, char *buffer)
+inline char *prom_nextprop(phandle node, const char *oprop, char *buffer)
{
unsigned long args[7];
char buf[32];
@@ -288,8 +289,7 @@ inline char *prom_nextprop(int node, const char *oprop, char *buffer)
}
EXPORT_SYMBOL(prom_nextprop);
-int
-prom_finddevice(const char *name)
+phandle prom_finddevice(const char *name)
{
unsigned long args[5];
@@ -307,7 +307,7 @@ prom_finddevice(const char *name)
}
EXPORT_SYMBOL(prom_finddevice);
-int prom_node_has_property(int node, const char *prop)
+int prom_node_has_property(phandle node, const char *prop)
{
char buf [32];
@@ -325,7 +325,7 @@ EXPORT_SYMBOL(prom_node_has_property);
* of 'size' bytes. Return the number of bytes the prom accepted.
*/
int
-prom_setprop(int node, const char *pname, char *value, int size)
+prom_setprop(phandle node, const char *pname, char *value, int size)
{
unsigned long args[8];
@@ -355,10 +355,10 @@ prom_setprop(int node, const char *pname, char *value, int size)
}
EXPORT_SYMBOL(prom_setprop);
-inline int prom_inst2pkg(int inst)
+inline phandle prom_inst2pkg(int inst)
{
unsigned long args[5];
- int node;
+ phandle node;
args[0] = (unsigned long) "instance-to-package";
args[1] = 1;
@@ -377,10 +377,10 @@ inline int prom_inst2pkg(int inst)
/* Return 'node' assigned to a particular prom 'path'
* FIXME: Should work for v0 as well
*/
-int
-prom_pathtoinode(const char *path)
+phandle prom_pathtoinode(const char *path)
{
- int node, inst;
+ phandle node;
+ int inst;
inst = prom_devopen (path);
if (inst == 0)
diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h
index 101229b0d8ed..42a978c0c1b3 100644
--- a/arch/x86/include/asm/olpc.h
+++ b/arch/x86/include/asm/olpc.h
@@ -89,6 +89,8 @@ extern int olpc_ec_mask_unset(uint8_t bits);
/* EC commands */
#define EC_FIRMWARE_REV 0x08
+#define EC_WLAN_ENTER_RESET 0x35
+#define EC_WLAN_LEAVE_RESET 0x25
/* SCI source values */
diff --git a/block/blk-core.c b/block/blk-core.c
index 881fe44ec7da..f0834e2f5727 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -64,15 +64,13 @@ static void drive_stat_acct(struct request *rq, int new_io)
return;
cpu = part_stat_lock();
+ part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq));
- if (!new_io) {
- part = rq->part;
+ if (!new_io)
part_stat_inc(cpu, part, merges[rw]);
- } else {
- part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq));
+ else {
part_round_stats(cpu, part);
part_inc_in_flight(part, rw);
- rq->part = part;
}
part_stat_unlock();
@@ -130,7 +128,6 @@ void blk_rq_init(struct request_queue *q, struct request *rq)
rq->ref_count = 1;
rq->start_time = jiffies;
set_start_time_ns(rq);
- rq->part = NULL;
}
EXPORT_SYMBOL(blk_rq_init);
@@ -805,16 +802,11 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
rl->starved[is_sync] = 0;
priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
- if (priv) {
+ if (priv)
rl->elvpriv++;
- /*
- * Don't do stats for non-priv requests
- */
- if (blk_queue_io_stat(q))
- rw_flags |= REQ_IO_STAT;
- }
-
+ if (blk_queue_io_stat(q))
+ rw_flags |= REQ_IO_STAT;
spin_unlock_irq(q->queue_lock);
rq = blk_alloc_request(q, rw_flags, priv, gfp_mask);
@@ -1791,7 +1783,7 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes)
int cpu;
cpu = part_stat_lock();
- part = req->part;
+ part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
part_stat_add(cpu, part, sectors[rw], bytes >> 9);
part_stat_unlock();
}
@@ -1811,7 +1803,7 @@ static void blk_account_io_done(struct request *req)
int cpu;
cpu = part_stat_lock();
- part = req->part;
+ part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
part_stat_inc(cpu, part, ios[rw]);
part_stat_add(cpu, part, ticks[rw], duration);
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 0a2fd8a48a38..77b7c26df6b5 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -351,7 +351,7 @@ static void blk_account_io_merge(struct request *req)
int cpu;
cpu = part_stat_lock();
- part = req->part;
+ part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
part_round_stats(cpu, part);
part_dec_in_flight(part, rq_data_dir(req));
diff --git a/block/blk.h b/block/blk.h
index 1e675e5ade02..2db8f32838e7 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -116,6 +116,10 @@ void blk_queue_congestion_threshold(struct request_queue *q);
int blk_dev_init(void);
+void elv_quiesce_start(struct request_queue *q);
+void elv_quiesce_end(struct request_queue *q);
+
+
/*
* Return the threshold (number of used requests) at which the queue is
* considered to be congested. It include a little hysteresis to keep the
diff --git a/block/genhd.c b/block/genhd.c
index a8adf96a4b41..5fa2b44a72ff 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -929,15 +929,8 @@ static void disk_free_ptbl_rcu_cb(struct rcu_head *head)
{
struct disk_part_tbl *ptbl =
container_of(head, struct disk_part_tbl, rcu_head);
- struct gendisk *disk = ptbl->disk;
- struct request_queue *q = disk->queue;
- unsigned long flags;
kfree(ptbl);
-
- spin_lock_irqsave(q->queue_lock, flags);
- elv_quiesce_end(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
}
/**
@@ -955,17 +948,11 @@ static void disk_replace_part_tbl(struct gendisk *disk,
struct disk_part_tbl *new_ptbl)
{
struct disk_part_tbl *old_ptbl = disk->part_tbl;
- struct request_queue *q = disk->queue;
rcu_assign_pointer(disk->part_tbl, new_ptbl);
if (old_ptbl) {
rcu_assign_pointer(old_ptbl->last_lookup, NULL);
-
- spin_lock_irq(q->queue_lock);
- elv_quiesce_start(q);
- spin_unlock_irq(q->queue_lock);
-
call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb);
}
}
@@ -1006,7 +993,6 @@ int disk_expand_part_tbl(struct gendisk *disk, int partno)
return -ENOMEM;
new_ptbl->len = target;
- new_ptbl->disk = disk;
for (i = 0; i < len; i++)
rcu_assign_pointer(new_ptbl->part[i], old_ptbl->part[i]);
diff --git a/drivers/Makefile b/drivers/Makefile
index a2aea53a75ed..14cf9077bb2b 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -51,7 +51,6 @@ obj-y += net/
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_FUSION) += message/
obj-y += firewire/
-obj-y += ieee1394/
obj-$(CONFIG_UIO) += uio/
obj-y += cdrom/
obj-y += auxdisplay/
@@ -92,6 +91,7 @@ obj-$(CONFIG_EISA) += eisa/
obj-y += lguest/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_CPU_IDLE) += cpuidle/
+obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_MEMSTICK) += memstick/
obj-$(CONFIG_NEW_LEDS) += leds/
@@ -104,7 +104,6 @@ obj-$(CONFIG_ARCH_SHMOBILE) += sh/
ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
obj-y += clocksource/
endif
-obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_DCA) += dca/
obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 3966e62ad019..f051cfff18af 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -147,6 +147,7 @@ static void platform_device_release(struct device *dev)
struct platform_object *pa = container_of(dev, struct platform_object,
pdev.dev);
+ of_device_node_put(&pa->pdev.dev);
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.resource);
kfree(pa);
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 6e968cd4893c..829161edae53 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -1225,7 +1225,8 @@ ace_of_probe(struct platform_device *op, const struct of_device_id *match)
bus_width = ACE_BUS_WIDTH_8;
/* Call the bus-independant setup code */
- return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width);
+ return ace_alloc(&op->dev, id ? be32_to_cpup(id) : 0,
+ physaddr, irq, bus_width);
}
static int __devexit ace_of_remove(struct platform_device *op)
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index a7ca75212bfe..e95d7876ca6b 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -175,8 +175,7 @@ EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
*/
struct getset_keycode_data {
- unsigned int scancode;
- unsigned int keycode;
+ struct input_keymap_entry ke;
int error;
};
@@ -184,32 +183,50 @@ static int getkeycode_helper(struct input_handle *handle, void *data)
{
struct getset_keycode_data *d = data;
- d->error = input_get_keycode(handle->dev, d->scancode, &d->keycode);
+ d->error = input_get_keycode(handle->dev, &d->ke);
return d->error == 0; /* stop as soon as we successfully get one */
}
int getkeycode(unsigned int scancode)
{
- struct getset_keycode_data d = { scancode, 0, -ENODEV };
+ struct getset_keycode_data d = {
+ .ke = {
+ .flags = 0,
+ .len = sizeof(scancode),
+ .keycode = 0,
+ },
+ .error = -ENODEV,
+ };
+
+ memcpy(d.ke.scancode, &scancode, sizeof(scancode));
input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
- return d.error ?: d.keycode;
+ return d.error ?: d.ke.keycode;
}
static int setkeycode_helper(struct input_handle *handle, void *data)
{
struct getset_keycode_data *d = data;
- d->error = input_set_keycode(handle->dev, d->scancode, d->keycode);
+ d->error = input_set_keycode(handle->dev, &d->ke);
return d->error == 0; /* stop as soon as we successfully set one */
}
int setkeycode(unsigned int scancode, unsigned int keycode)
{
- struct getset_keycode_data d = { scancode, keycode, -ENODEV };
+ struct getset_keycode_data d = {
+ .ke = {
+ .flags = 0,
+ .len = sizeof(scancode),
+ .keycode = keycode,
+ },
+ .error = -ENODEV,
+ };
+
+ memcpy(d.ke.scancode, &scancode, sizeof(scancode));
input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index f3019f53e875..eaa5d3efa79d 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -566,10 +566,16 @@ static const unsigned char sysrq_xlate[KEY_MAX + 1] =
static bool sysrq_down;
static int sysrq_alt_use;
static int sysrq_alt;
+static DEFINE_SPINLOCK(sysrq_event_lock);
static bool sysrq_filter(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
+ bool suppress;
+
+ /* We are called with interrupts disabled, just take the lock */
+ spin_lock(&sysrq_event_lock);
+
if (type != EV_KEY)
goto out;
@@ -601,7 +607,10 @@ static bool sysrq_filter(struct input_handle *handle, unsigned int type,
}
out:
- return sysrq_down;
+ suppress = sysrq_down;
+ spin_unlock(&sysrq_event_lock);
+
+ return suppress;
}
static int sysrq_connect(struct input_handler *handler,
@@ -652,8 +661,8 @@ static void sysrq_disconnect(struct input_handle *handle)
}
/*
- * We are matching on KEY_LEFTALT insteard of KEY_SYSRQ because not all
- * keyboards have SysRq ikey predefined and so user may add it to keymap
+ * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
+ * keyboards have SysRq key predefined and so user may add it to keymap
* later, but we expect all such keyboards to have left alt.
*/
static const struct input_device_id sysrq_ids[] = {
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 717305d30444..a44611652282 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -308,7 +308,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
* isr before we end up here.
*/
if (p->flags & FLAG_CLOCKSOURCE)
- p->total_cycles += p->match_value;
+ p->total_cycles += p->match_value + 1;
if (!(p->flags & FLAG_REPROGRAM))
p->next_match_value = p->max_match_value;
@@ -403,7 +403,7 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
raw = sh_cmt_get_counter(p, &has_wrapped);
if (unlikely(has_wrapped))
- raw += p->match_value;
+ raw += p->match_value + 1;
spin_unlock_irqrestore(&p->lock, flags);
return value + raw;
@@ -445,7 +445,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
/* clk_get_rate() needs an enabled clock */
clk_enable(p->clk);
- p->rate = clk_get_rate(p->clk) / (p->width == 16) ? 512 : 8;
+ p->rate = clk_get_rate(p->clk) / ((p->width == 16) ? 512 : 8);
clk_disable(p->clk);
/* TODO: calculate good shift from rate and counter bit width */
@@ -478,7 +478,7 @@ static void sh_cmt_clock_event_start(struct sh_cmt_priv *p, int periodic)
ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
if (periodic)
- sh_cmt_set_next(p, (p->rate + HZ/2) / HZ);
+ sh_cmt_set_next(p, ((p->rate + HZ/2) / HZ) - 1);
else
sh_cmt_set_next(p, p->max_match_value);
}
@@ -523,9 +523,9 @@ static int sh_cmt_clock_event_next(unsigned long delta,
BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
if (likely(p->flags & FLAG_IRQCONTEXT))
- p->next_match_value = delta;
+ p->next_match_value = delta - 1;
else
- sh_cmt_set_next(p, delta);
+ sh_cmt_set_next(p, delta - 1);
return 0;
}
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index fcf3ea28340b..40a222e19b2d 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -3,9 +3,6 @@ menu "IEEE 1394 (FireWire) support"
# firewire-core does not depend on PCI but is
# not useful without PCI controller driver
-comment "You can enable one or both FireWire driver stacks."
-comment "The newer stack is recommended."
-
config FIREWIRE
tristate "FireWire driver stack"
select CRC_ITU_T
@@ -64,8 +61,6 @@ config FIREWIRE_NET
To compile this driver as a module, say M here: The module will be
called firewire-net.
-source "drivers/ieee1394/Kconfig"
-
config FIREWIRE_NOSY
tristate "Nosy - a FireWire traffic sniffer for PCILynx cards"
depends on PCI
diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile
index 3c6a7fb20aa7..e3870d5c43dd 100644
--- a/drivers/firewire/Makefile
+++ b/drivers/firewire/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o
obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o
obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o
+obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
diff --git a/drivers/ieee1394/init_ohci1394_dma.c b/drivers/firewire/init_ohci1394_dma.c
index ddaab6eb8ace..a9a347adb353 100644
--- a/drivers/ieee1394/init_ohci1394_dma.c
+++ b/drivers/firewire/init_ohci1394_dma.c
@@ -32,23 +32,41 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include <linux/interrupt.h> /* for ohci1394.h */
#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
#include <linux/pci.h> /* for PCI defines */
-#include <linux/init_ohci1394_dma.h>
+#include <linux/string.h>
+
#include <asm/pci-direct.h> /* for direct PCI config space access */
#include <asm/fixmap.h>
-#include "ieee1394_types.h"
-#include "ohci1394.h"
+#include <linux/init_ohci1394_dma.h>
+#include "ohci.h"
int __initdata init_ohci1394_dma_early;
+struct ohci {
+ void __iomem *registers;
+};
+
+static inline void reg_write(const struct ohci *ohci, int offset, u32 data)
+{
+ writel(data, ohci->registers + offset);
+}
+
+static inline u32 reg_read(const struct ohci *ohci, int offset)
+{
+ return readl(ohci->registers + offset);
+}
+
+#define OHCI_LOOP_COUNT 100 /* Number of loops for reg read waits */
+
/* Reads a PHY register of an OHCI-1394 controller */
-static inline u8 __init get_phy_reg(struct ti_ohci *ohci, u8 addr)
+static inline u8 __init get_phy_reg(struct ohci *ohci, u8 addr)
{
int i;
- quadlet_t r;
+ u32 r;
reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
@@ -63,22 +81,22 @@ static inline u8 __init get_phy_reg(struct ti_ohci *ohci, u8 addr)
}
/* Writes to a PHY register of an OHCI-1394 controller */
-static inline void __init set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
+static inline void __init set_phy_reg(struct ohci *ohci, u8 addr, u8 data)
{
int i;
reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- u32 r = reg_read(ohci, OHCI1394_PhyControl);
- if (!(r & 0x00004000))
+ if (!(reg_read(ohci, OHCI1394_PhyControl) & 0x00004000))
break;
mdelay(1);
}
}
/* Resets an OHCI-1394 controller (for sane state before initialization) */
-static inline void __init init_ohci1394_soft_reset(struct ti_ohci *ohci) {
+static inline void __init init_ohci1394_soft_reset(struct ohci *ohci)
+{
int i;
reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
@@ -91,10 +109,14 @@ static inline void __init init_ohci1394_soft_reset(struct ti_ohci *ohci) {
}
}
+#define OHCI1394_MAX_AT_REQ_RETRIES 0xf
+#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
+#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
+
/* Basic OHCI-1394 register and port inititalization */
-static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
+static inline void __init init_ohci1394_initialize(struct ohci *ohci)
{
- quadlet_t bus_options;
+ u32 bus_options;
int num_ports, i;
/* Put some defaults to these undefined bus options */
@@ -116,7 +138,7 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
/* enable phys */
reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_RcvPhyPkt);
+ OHCI1394_LinkControl_rcvPhyPkt);
/* Don't accept phy packets into AR request context */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
@@ -128,7 +150,7 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
/* Accept asyncronous transfer requests from all nodes for now */
- reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
+ reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
/* Specify asyncronous transfer retries */
reg_write(ohci, OHCI1394_ATRetries,
@@ -137,7 +159,8 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
(OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
/* We don't want hardware swapping */
- reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
+ reg_write(ohci, OHCI1394_HCControlClear,
+ OHCI1394_HCControl_noByteSwapData);
/* Enable link */
reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
@@ -164,11 +187,11 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
* has to be enabled after each bus reset when needed. We resort
* to polling here because on early boot, we have no interrupts.
*/
-static inline void __init init_ohci1394_wait_for_busresets(struct ti_ohci *ohci)
+static inline void __init init_ohci1394_wait_for_busresets(struct ohci *ohci)
{
int i, events;
- for (i=0; i < 9; i++) {
+ for (i = 0; i < 9; i++) {
mdelay(200);
events = reg_read(ohci, OHCI1394_IntEventSet);
if (events & OHCI1394_busReset)
@@ -182,18 +205,18 @@ static inline void __init init_ohci1394_wait_for_busresets(struct ti_ohci *ohci)
* This enables remote DMA access over IEEE1394 from every host for the low
* 4GB of address space. DMA accesses above 4GB are not available currently.
*/
-static inline void __init init_ohci1394_enable_physical_dma(struct ti_ohci *hci)
+static inline void __init init_ohci1394_enable_physical_dma(struct ohci *ohci)
{
- reg_write(hci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
- reg_write(hci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
- reg_write(hci, OHCI1394_PhyUpperBound, 0xffff0000);
+ reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
+ reg_write(ohci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
+ reg_write(ohci, OHCI1394_PhyUpperBound, 0xffff0000);
}
/**
* init_ohci1394_reset_and_init_dma - init controller and enable DMA
* This initializes the given controller and enables physical DMA engine in it.
*/
-static inline void __init init_ohci1394_reset_and_init_dma(struct ti_ohci *ohci)
+static inline void __init init_ohci1394_reset_and_init_dma(struct ohci *ohci)
{
/* Start off with a soft reset, clears everything to a sane state. */
init_ohci1394_soft_reset(ohci);
@@ -225,7 +248,7 @@ static inline void __init init_ohci1394_reset_and_init_dma(struct ti_ohci *ohci)
static inline void __init init_ohci1394_controller(int num, int slot, int func)
{
unsigned long ohci_base;
- struct ti_ohci ohci;
+ struct ohci ohci;
printk(KERN_INFO "init_ohci1394_dma: initializing OHCI-1394"
" at %02x:%02x.%x\n", num, slot, func);
@@ -235,7 +258,7 @@ static inline void __init init_ohci1394_controller(int num, int slot, int func)
set_fixmap_nocache(FIX_OHCI1394_BASE, ohci_base);
- ohci.registers = (void *)fix_to_virt(FIX_OHCI1394_BASE);
+ ohci.registers = (void __iomem *)fix_to_virt(FIX_OHCI1394_BASE);
init_ohci1394_reset_and_init_dma(&ohci);
}
@@ -247,6 +270,7 @@ static inline void __init init_ohci1394_controller(int num, int slot, int func)
void __init init_ohci1394_dma_on_all_controllers(void)
{
int num, slot, func;
+ u32 class;
if (!early_pci_allowed())
return;
@@ -255,9 +279,9 @@ void __init init_ohci1394_dma_on_all_controllers(void)
for (num = 0; num < 32; num++) {
for (slot = 0; slot < 32; slot++) {
for (func = 0; func < 8; func++) {
- u32 class = read_pci_config(num,slot,func,
+ class = read_pci_config(num, slot, func,
PCI_CLASS_REVISION);
- if ((class == 0xffffffff))
+ if (class == 0xffffffff)
continue; /* No device at this func */
if (class>>8 != PCI_CLASS_SERIAL_FIREWIRE_OHCI)
diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c
index 709690995d0d..846fbd5e31bf 100644
--- a/drivers/gpio/xilinx_gpio.c
+++ b/drivers/gpio/xilinx_gpio.c
@@ -171,13 +171,13 @@ static int __devinit xgpio_of_probe(struct device_node *np)
/* Update GPIO state shadow register with default value */
tree_info = of_get_property(np, "xlnx,dout-default", NULL);
if (tree_info)
- chip->gpio_state = *tree_info;
+ chip->gpio_state = be32_to_cpup(tree_info);
/* Update GPIO direction shadow register with default value */
chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */
tree_info = of_get_property(np, "xlnx,tri-default", NULL);
if (tree_info)
- chip->gpio_dir = *tree_info;
+ chip->gpio_dir = be32_to_cpup(tree_info);
/* Check device node and parent device node for device width */
chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */
@@ -186,7 +186,7 @@ static int __devinit xgpio_of_probe(struct device_node *np)
tree_info = of_get_property(np->parent,
"xlnx,gpio-width", NULL);
if (tree_info)
- chip->mmchip.gc.ngpio = *tree_info;
+ chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
spin_lock_init(&chip->gpio_lock);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 7832b6e2478b..515345b11ac9 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1780,6 +1780,11 @@ static bool hid_ignore(struct hid_device *hdev)
hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST)
return true;
break;
+ case USB_VENDOR_ID_HANWANG:
+ if (hdev->product >= USB_DEVICE_ID_HANWANG_TABLET_FIRST &&
+ hdev->product <= USB_DEVICE_ID_HANWANG_TABLET_LAST)
+ return true;
+ break;
}
if (hdev->type == HID_TYPE_USBMOUSE &&
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 3ee999d33004..3341baa86a30 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -299,6 +299,10 @@
#define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003
#define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008
+#define USB_VENDOR_ID_HANWANG 0x0b57
+#define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000
+#define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff
+
#define USB_VENDOR_ID_HAPP 0x078b
#define USB_DEVICE_ID_UGCI_DRIVING 0x0010
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 834ef47b76d6..bb0b3659437b 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -68,39 +68,52 @@ static const struct {
#define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \
&max, EV_KEY, (c))
-static inline int match_scancode(unsigned int code, unsigned int scancode)
+static bool match_scancode(struct hid_usage *usage,
+ unsigned int cur_idx, unsigned int scancode)
{
- if (scancode == 0)
- return 1;
-
- return (code & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
+ return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
}
-static inline int match_keycode(unsigned int code, unsigned int keycode)
+static bool match_keycode(struct hid_usage *usage,
+ unsigned int cur_idx, unsigned int keycode)
{
- if (keycode == 0)
- return 1;
+ /*
+ * We should exclude unmapped usages when doing lookup by keycode.
+ */
+ return (usage->type == EV_KEY && usage->code == keycode);
+}
- return code == keycode;
+static bool match_index(struct hid_usage *usage,
+ unsigned int cur_idx, unsigned int idx)
+{
+ return cur_idx == idx;
}
+typedef bool (*hid_usage_cmp_t)(struct hid_usage *usage,
+ unsigned int cur_idx, unsigned int val);
+
static struct hid_usage *hidinput_find_key(struct hid_device *hid,
- unsigned int scancode,
- unsigned int keycode)
+ hid_usage_cmp_t match,
+ unsigned int value,
+ unsigned int *usage_idx)
{
- int i, j, k;
+ unsigned int i, j, k, cur_idx = 0;
struct hid_report *report;
struct hid_usage *usage;
for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
for (i = 0; i < report->maxfield; i++) {
- for ( j = 0; j < report->field[i]->maxusage; j++) {
+ for (j = 0; j < report->field[i]->maxusage; j++) {
usage = report->field[i]->usage + j;
- if (usage->type == EV_KEY &&
- match_scancode(usage->hid, scancode) &&
- match_keycode(usage->code, keycode))
- return usage;
+ if (usage->type == EV_KEY || usage->type == 0) {
+ if (match(usage, cur_idx, value)) {
+ if (usage_idx)
+ *usage_idx = cur_idx;
+ return usage;
+ }
+ cur_idx++;
+ }
}
}
}
@@ -108,39 +121,68 @@ static struct hid_usage *hidinput_find_key(struct hid_device *hid,
return NULL;
}
+static struct hid_usage *hidinput_locate_usage(struct hid_device *hid,
+ const struct input_keymap_entry *ke,
+ unsigned int *index)
+{
+ struct hid_usage *usage;
+ unsigned int scancode;
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+ usage = hidinput_find_key(hid, match_index, ke->index, index);
+ else if (input_scancode_to_scalar(ke, &scancode) == 0)
+ usage = hidinput_find_key(hid, match_scancode, scancode, index);
+ else
+ usage = NULL;
+
+ return usage;
+}
+
static int hidinput_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
+ struct input_keymap_entry *ke)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hid_usage *usage;
+ unsigned int scancode, index;
- usage = hidinput_find_key(hid, scancode, 0);
+ usage = hidinput_locate_usage(hid, ke, &index);
if (usage) {
- *keycode = usage->code;
+ ke->keycode = usage->type == EV_KEY ?
+ usage->code : KEY_RESERVED;
+ ke->index = index;
+ scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE);
+ ke->len = sizeof(scancode);
+ memcpy(ke->scancode, &scancode, sizeof(scancode));
return 0;
}
+
return -EINVAL;
}
static int hidinput_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hid_usage *usage;
- int old_keycode;
- usage = hidinput_find_key(hid, scancode, 0);
+ usage = hidinput_locate_usage(hid, ke, NULL);
if (usage) {
- old_keycode = usage->code;
- usage->code = keycode;
+ *old_keycode = usage->type == EV_KEY ?
+ usage->code : KEY_RESERVED;
+ usage->code = ke->keycode;
- clear_bit(old_keycode, dev->keybit);
+ clear_bit(*old_keycode, dev->keybit);
set_bit(usage->code, dev->keybit);
- dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
- /* Set the keybit for the old keycode if the old keycode is used
- * by another key */
- if (hidinput_find_key (hid, 0, old_keycode))
- set_bit(old_keycode, dev->keybit);
+ dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n",
+ usage->code, usage->hid);
+
+ /*
+ * Set the keybit for the old keycode if the old keycode is used
+ * by another key
+ */
+ if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL))
+ set_bit(*old_keycode, dev->keybit);
return 0;
}
@@ -835,8 +877,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
hid->ll_driver->hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
- input_dev->setkeycode = hidinput_setkeycode;
- input_dev->getkeycode = hidinput_getkeycode;
+ input_dev->setkeycode_new = hidinput_setkeycode;
+ input_dev->getkeycode_new = hidinput_getkeycode;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 97499d00615a..e382da3122b7 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1088,26 +1088,6 @@ config SENSORS_ULTRA45
This driver provides support for the Ultra45 workstation environmental
sensors.
-config SENSORS_HDAPS
- tristate "IBM Hard Drive Active Protection System (hdaps)"
- depends on INPUT && X86
- select INPUT_POLLDEV
- default n
- help
- This driver provides support for the IBM Hard Drive Active Protection
- System (hdaps), which provides an accelerometer and other misc. data.
- ThinkPads starting with the R50, T41, and X40 are supported. The
- accelerometer data is readable via sysfs.
-
- This driver also provides an absolute input class device, allowing
- the laptop to act as a pinball machine-esque joystick.
-
- If your ThinkPad is not recognized by the driver, please update to latest
- BIOS. This is especially the case for some R52 ThinkPads.
-
- Say Y here if you have an applicable laptop and want to experience
- the awesome power of hdaps.
-
config SENSORS_LIS3_SPI
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
depends on !ACPI && SPI_MASTER && INPUT
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index e3c2484f6c5f..ec9cb735c898 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -52,7 +52,6 @@ obj-$(CONFIG_SENSORS_G760A) += g760a.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
-obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
index 4f93da31d3ad..3cad8fecc3d3 100644
--- a/drivers/i2c/busses/i2c-sh7760.c
+++ b/drivers/i2c/busses/i2c-sh7760.c
@@ -101,12 +101,12 @@ struct cami2c {
static inline void OUT32(struct cami2c *cam, int reg, unsigned long val)
{
- ctrl_outl(val, (unsigned long)cam->iobase + reg);
+ __raw_writel(val, (unsigned long)cam->iobase + reg);
}
static inline unsigned long IN32(struct cami2c *cam, int reg)
{
- return ctrl_inl((unsigned long)cam->iobase + reg);
+ return __raw_readl((unsigned long)cam->iobase + reg);
}
static irqreturn_t sh7760_i2c_irq(int irq, void *ptr)
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 598c49acaeb5..2707f5e17158 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -538,15 +538,17 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
{
struct resource *res;
int ret = -ENXIO;
- int q, m;
- int k = 0;
- int n = 0;
+ int n, k = 0;
while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
for (n = res->start; hook && n <= res->end; n++) {
if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED,
- dev_name(&dev->dev), dev))
+ dev_name(&dev->dev), dev)) {
+ for (n--; n >= res->start; n--)
+ free_irq(n, dev);
+
goto rollback;
+ }
}
k++;
}
@@ -554,16 +556,17 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
if (hook)
return k > 0 ? 0 : -ENOENT;
- k--;
ret = 0;
rollback:
- for (q = k; k >= 0; k--) {
- for (m = n; m >= res->start; m--)
- free_irq(m, dev);
+ k--;
+
+ while (k >= 0) {
+ res = platform_get_resource(dev, IORESOURCE_IRQ, k);
+ for (n = res->start; n <= res->end; n++)
+ free_irq(n, dev);
- res = platform_get_resource(dev, IORESOURCE_IRQ, k - 1);
- m = res->end;
+ k--;
}
return ret;
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
deleted file mode 100644
index e02096cf7d95..000000000000
--- a/drivers/ieee1394/Kconfig
+++ /dev/null
@@ -1,182 +0,0 @@
-config IEEE1394
- tristate "Legacy alternative FireWire driver stack"
- depends on PCI || BROKEN
- help
- IEEE 1394 describes a high performance serial bus, which is also
- known as FireWire(tm) or i.Link(tm) and is used for connecting all
- sorts of devices (most notably digital video cameras) to your
- computer.
-
- If you have FireWire hardware and want to use it, say Y here. This
- is the core support only, you will also need to select a driver for
- your IEEE 1394 adapter.
-
- To compile this driver as a module, say M here: the module will be
- called ieee1394.
-
- NOTE:
- ieee1394 is superseded by the newer firewire-core driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_OHCI1394
- tristate "OHCI-1394 controllers"
- depends on PCI && IEEE1394
- help
- Enable this driver if you have an IEEE 1394 controller based on the
- OHCI-1394 specification. The current driver is only tested with OHCI
- chipsets made by Texas Instruments and NEC. Most third-party vendors
- use one of these chipsets. It should work with any OHCI-1394
- compliant card, however.
-
- To compile this driver as a module, say M here: the module will be
- called ohci1394.
-
- NOTE:
- ohci1394 is superseded by the newer firewire-ohci driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
- If you want to install firewire-ohci and ohci1394 together, you
- should configure them only as modules and blacklist the driver(s)
- which you don't want to have auto-loaded. Add either
-
- blacklist ohci1394
- blacklist video1394
- blacklist dv1394
- or
- blacklist firewire-ohci
-
- to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf
- depending on your distribution.
-
-comment "PCILynx controller requires I2C"
- depends on IEEE1394 && I2C=n
-
-config IEEE1394_PCILYNX
- tristate "PCILynx controller"
- depends on PCI && IEEE1394 && I2C
- select I2C_ALGOBIT
- help
- Say Y here if you have an IEEE-1394 controller with the Texas
- Instruments PCILynx chip. Note: this driver is written for revision
- 2 of this chip and may not work with revision 0.
-
- To compile this driver as a module, say M here: the module will be
- called pcilynx.
-
- Only some old and now very rare PCI and CardBus cards and
- PowerMacs G3 B&W contain the PCILynx controller. Therefore
- almost everybody can say N here.
-
-comment "SBP-2 support (for storage devices) requires SCSI"
- depends on IEEE1394 && SCSI=n
-
-config IEEE1394_SBP2
- tristate "Storage devices (SBP-2 protocol)"
- depends on IEEE1394 && SCSI
- help
- This option enables you to use SBP-2 devices connected to an IEEE
- 1394 bus. SBP-2 devices include storage devices like harddisks and
- DVD drives, also some other FireWire devices like scanners.
-
- You should also enable support for disks, CD-ROMs, etc. in the SCSI
- configuration section.
-
- To compile this driver as a module, say M here: the module will be
- called sbp2.
-
- NOTE:
- sbp2 is superseded by the newer firewire-sbp2 driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_SBP2_PHYS_DMA
- bool "Enable replacement for physical DMA in SBP2"
- depends on IEEE1394_SBP2 && VIRT_TO_BUS && EXPERIMENTAL
- help
- This builds sbp2 for use with non-OHCI host adapters which do not
- support physical DMA or for when ohci1394 is run with phys_dma=0.
- Physical DMA is data movement without assistance of the drivers'
- interrupt handlers. This option includes the interrupt handlers
- that are required in absence of this hardware feature.
-
- This option is buggy and currently broken on some architectures.
- If unsure, say N.
-
-config IEEE1394_ETH1394_ROM_ENTRY
- depends on IEEE1394
- bool
- default n
-
-config IEEE1394_ETH1394
- tristate "IP networking over 1394 (experimental)"
- depends on IEEE1394 && EXPERIMENTAL && INET
- select IEEE1394_ETH1394_ROM_ENTRY
- help
- This driver implements a functional majority of RFC 2734: IPv4 over
- 1394. It will provide IP connectivity with implementations of RFC
- 2734 found on other operating systems. It will not communicate with
- older versions of this driver found in stock kernels prior to 2.6.3.
- This driver is still considered experimental. It does not yet support
- MCAP, therefore multicast support is significantly limited.
-
- The module is called eth1394 although it does not emulate Ethernet.
-
- NOTE:
- eth1394 is superseded by the newer firewire-net driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_RAWIO
- tristate "raw1394 userspace interface"
- depends on IEEE1394
- help
- This option adds support for the raw1394 device file which enables
- direct communication of user programs with IEEE 1394 devices
- (isochronous and asynchronous). Almost all application programs
- which access FireWire require this option.
-
- To compile this driver as a module, say M here: the module will be
- called raw1394.
-
- NOTE:
- raw1394 is superseded by the newer firewire-core driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_VIDEO1394
- tristate "video1394 userspace interface"
- depends on IEEE1394 && IEEE1394_OHCI1394
- help
- This option adds support for the video1394 device files which enable
- isochronous communication of user programs with IEEE 1394 devices,
- especially video capture or export. This interface is used by all
- libdc1394 based programs and by several other programs, in addition to
- the raw1394 interface. It is generally not required for DV capture.
-
- To compile this driver as a module, say M here: the module will be
- called video1394.
-
- NOTE:
- video1394 is superseded by the newer firewire-core driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_DV1394
- tristate "dv1394 userspace interface (deprecated)"
- depends on IEEE1394 && IEEE1394_OHCI1394
- help
- The dv1394 driver is unsupported and may be removed from Linux in a
- future release. Its functionality is now provided by either
- raw1394 or firewire-core together with libraries such as libiec61883.
-
-config IEEE1394_VERBOSEDEBUG
- bool "Excessive debugging output"
- depends on IEEE1394
- help
- If you say Y here, you will get very verbose debugging logs from the
- ieee1394 drivers, including sent and received packet headers. This
- will quickly result in large amounts of data sent to the system log.
-
- Say Y if you really need the debugging output. Everyone else says N.
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
deleted file mode 100644
index 1f8153b57503..000000000000
--- a/drivers/ieee1394/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the Linux IEEE 1394 implementation
-#
-
-ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
- highlevel.o csr.o nodemgr.o dma.o iso.o \
- csr1212.o config_roms.o
-
-obj-$(CONFIG_IEEE1394) += ieee1394.o
-obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
-obj-$(CONFIG_IEEE1394_OHCI1394) += ohci1394.o
-obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
-obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
-obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
-obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
-obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
-
-obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
diff --git a/drivers/ieee1394/config_roms.c b/drivers/ieee1394/config_roms.c
deleted file mode 100644
index 1b981207fa76..000000000000
--- a/drivers/ieee1394/config_roms.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * ConfigROM entries
- *
- * Copyright (C) 2004 Ben Collins
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/types.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "csr.h"
-#include "config_roms.h"
-
-struct hpsb_config_rom_entry {
- const char *name;
-
- /* Base initialization, called at module load */
- int (*init)(void);
-
- /* Cleanup called at module exit */
- void (*cleanup)(void);
-
- /* The flag added to host->config_roms */
- unsigned int flag;
-};
-
-/* The default host entry. This must succeed. */
-int hpsb_default_host_entry(struct hpsb_host *host)
-{
- struct csr1212_keyval *root;
- struct csr1212_keyval *vend_id = NULL;
- struct csr1212_keyval *text = NULL;
- char csr_name[128];
- int ret;
-
- sprintf(csr_name, "Linux - %s", host->driver->name);
- root = host->csr.rom->root_kv;
-
- vend_id = csr1212_new_immediate(CSR1212_KV_ID_VENDOR, host->csr.guid_hi >> 8);
- text = csr1212_new_string_descriptor_leaf(csr_name);
-
- if (!vend_id || !text) {
- if (vend_id)
- csr1212_release_keyval(vend_id);
- if (text)
- csr1212_release_keyval(text);
- csr1212_destroy_csr(host->csr.rom);
- return -ENOMEM;
- }
-
- csr1212_associate_keyval(vend_id, text);
- csr1212_release_keyval(text);
- ret = csr1212_attach_keyval_to_directory(root, vend_id);
- csr1212_release_keyval(vend_id);
- if (ret != CSR1212_SUCCESS) {
- csr1212_destroy_csr(host->csr.rom);
- return -ENOMEM;
- }
-
- host->update_config_rom = 1;
-
- return 0;
-}
-
-
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
-#include "eth1394.h"
-
-static struct csr1212_keyval *ip1394_ud;
-
-static int config_rom_ip1394_init(void)
-{
- struct csr1212_keyval *spec_id = NULL;
- struct csr1212_keyval *spec_desc = NULL;
- struct csr1212_keyval *ver = NULL;
- struct csr1212_keyval *ver_desc = NULL;
- int ret = -ENOMEM;
-
- ip1394_ud = csr1212_new_directory(CSR1212_KV_ID_UNIT);
-
- spec_id = csr1212_new_immediate(CSR1212_KV_ID_SPECIFIER_ID,
- ETHER1394_GASP_SPECIFIER_ID);
- spec_desc = csr1212_new_string_descriptor_leaf("IANA");
- ver = csr1212_new_immediate(CSR1212_KV_ID_VERSION,
- ETHER1394_GASP_VERSION);
- ver_desc = csr1212_new_string_descriptor_leaf("IPv4");
-
- if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc)
- goto ip1394_fail;
-
- csr1212_associate_keyval(spec_id, spec_desc);
- csr1212_associate_keyval(ver, ver_desc);
- if (csr1212_attach_keyval_to_directory(ip1394_ud, spec_id)
- == CSR1212_SUCCESS &&
- csr1212_attach_keyval_to_directory(ip1394_ud, ver)
- == CSR1212_SUCCESS)
- ret = 0;
-
-ip1394_fail:
- if (ret && ip1394_ud) {
- csr1212_release_keyval(ip1394_ud);
- ip1394_ud = NULL;
- }
-
- if (spec_id)
- csr1212_release_keyval(spec_id);
- if (spec_desc)
- csr1212_release_keyval(spec_desc);
- if (ver)
- csr1212_release_keyval(ver);
- if (ver_desc)
- csr1212_release_keyval(ver_desc);
-
- return ret;
-}
-
-static void config_rom_ip1394_cleanup(void)
-{
- if (ip1394_ud) {
- csr1212_release_keyval(ip1394_ud);
- ip1394_ud = NULL;
- }
-}
-
-int hpsb_config_rom_ip1394_add(struct hpsb_host *host)
-{
- if (!ip1394_ud)
- return -ENODEV;
-
- if (csr1212_attach_keyval_to_directory(host->csr.rom->root_kv,
- ip1394_ud) != CSR1212_SUCCESS)
- return -ENOMEM;
-
- host->config_roms |= HPSB_CONFIG_ROM_ENTRY_IP1394;
- host->update_config_rom = 1;
- return 0;
-}
-EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_add);
-
-void hpsb_config_rom_ip1394_remove(struct hpsb_host *host)
-{
- csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud);
- host->config_roms &= ~HPSB_CONFIG_ROM_ENTRY_IP1394;
- host->update_config_rom = 1;
-}
-EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_remove);
-
-static struct hpsb_config_rom_entry ip1394_entry = {
- .name = "ip1394",
- .init = config_rom_ip1394_init,
- .cleanup = config_rom_ip1394_cleanup,
- .flag = HPSB_CONFIG_ROM_ENTRY_IP1394,
-};
-
-#endif /* CONFIG_IEEE1394_ETH1394_ROM_ENTRY */
-
-static struct hpsb_config_rom_entry *const config_rom_entries[] = {
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
- &ip1394_entry,
-#endif
-};
-
-/* Initialize all config roms */
-int hpsb_init_config_roms(void)
-{
- int i, error = 0;
-
- for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
- if (config_rom_entries[i]->init()) {
- HPSB_ERR("Failed to initialize config rom entry `%s'",
- config_rom_entries[i]->name);
- error = -1;
- }
-
- return error;
-}
-
-/* Cleanup all config roms */
-void hpsb_cleanup_config_roms(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
- config_rom_entries[i]->cleanup();
-}
diff --git a/drivers/ieee1394/config_roms.h b/drivers/ieee1394/config_roms.h
deleted file mode 100644
index 1f5cd1f16c44..000000000000
--- a/drivers/ieee1394/config_roms.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _IEEE1394_CONFIG_ROMS_H
-#define _IEEE1394_CONFIG_ROMS_H
-
-struct hpsb_host;
-
-int hpsb_default_host_entry(struct hpsb_host *host);
-int hpsb_init_config_roms(void);
-void hpsb_cleanup_config_roms(void);
-
-/* List of flags to check if a host contains a certain extra config rom
- * entry. Available in the host->config_roms member. */
-#define HPSB_CONFIG_ROM_ENTRY_IP1394 0x00000001
-
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
-int hpsb_config_rom_ip1394_add(struct hpsb_host *host);
-void hpsb_config_rom_ip1394_remove(struct hpsb_host *host);
-#endif
-
-#endif /* _IEEE1394_CONFIG_ROMS_H */
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
deleted file mode 100644
index d696f69ebce5..000000000000
--- a/drivers/ieee1394/csr.c
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * CSR implementation, iso/bus manager implementation.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- * 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * configuration ROM manipulation
- *
- */
-
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/param.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-
-#include "csr1212.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "highlevel.h"
-#include "ieee1394_core.h"
-
-/* Module Parameters */
-/* this module parameter can be used to disable mapping of the FCP registers */
-
-static int fcp = 1;
-module_param(fcp, int, 0444);
-MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
-
-static struct csr1212_keyval *node_cap = NULL;
-
-static void add_host(struct hpsb_host *host);
-static void remove_host(struct hpsb_host *host);
-static void host_reset(struct hpsb_host *host);
-static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 fl);
-static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
- quadlet_t *data, u64 addr, size_t length, u16 flags);
-static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
- u64 addr, size_t length, u16 flags);
-static int write_regs(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t *data, u64 addr, size_t length, u16 flags);
-static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl);
-static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
- u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl);
-static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 fl);
-static u64 allocate_addr_range(u64 size, u32 alignment, void *__host);
-static void release_addr_range(u64 addr, void *__host);
-
-static struct hpsb_highlevel csr_highlevel = {
- .name = "standard registers",
- .add_host = add_host,
- .remove_host = remove_host,
- .host_reset = host_reset,
-};
-
-static const struct hpsb_address_ops map_ops = {
- .read = read_maps,
-};
-
-static const struct hpsb_address_ops fcp_ops = {
- .write = write_fcp,
-};
-
-static const struct hpsb_address_ops reg_ops = {
- .read = read_regs,
- .write = write_regs,
- .lock = lock_regs,
- .lock64 = lock64_regs,
-};
-
-static const struct hpsb_address_ops config_rom_ops = {
- .read = read_config_rom,
-};
-
-struct csr1212_bus_ops csr_bus_ops = {
- .allocate_addr_range = allocate_addr_range,
- .release_addr = release_addr_range,
-};
-
-
-static u16 csr_crc16(unsigned *data, int length)
-{
- int check=0, i;
- int shift, sum, next=0;
-
- for (i = length; i; i--) {
- for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
- sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
- next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
- }
- check = next & 0xffff;
- data++;
- }
-
- return check;
-}
-
-static void host_reset(struct hpsb_host *host)
-{
- host->csr.state &= 0x300;
-
- host->csr.bus_manager_id = 0x3f;
- host->csr.bandwidth_available = 4915;
- host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */
- host->csr.channels_available_lo = ~0;
- host->csr.broadcast_channel = 0x80000000 | 31;
-
- if (host->is_irm) {
- if (host->driver->hw_csr_reg) {
- host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
- }
- }
-
- host->csr.node_ids = host->node_id << 16;
-
- if (!host->is_root) {
- /* clear cmstr bit */
- host->csr.state &= ~0x100;
- }
-
- be32_add_cpu(&host->csr.topology_map[1], 1);
- host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16
- | host->selfid_count);
- host->csr.topology_map[0] =
- cpu_to_be32((host->selfid_count + 2) << 16
- | csr_crc16(host->csr.topology_map + 1,
- host->selfid_count + 2));
-
- be32_add_cpu(&host->csr.speed_map[1], 1);
- host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16
- | csr_crc16(host->csr.speed_map+1,
- 0x3f1));
-}
-
-/*
- * HI == seconds (bits 0:2)
- * LO == fractions of a second in units of 125usec (bits 19:31)
- *
- * Convert SPLIT_TIMEOUT to jiffies.
- * The default and minimum as per 1394a-2000 clause 8.3.2.2.6 is 100ms.
- */
-static inline void calculate_expire(struct csr_control *csr)
-{
- unsigned int usecs = (csr->split_timeout_hi & 7) * 1000000 +
- (csr->split_timeout_lo >> 19) * 125;
-
- csr->expire = usecs_to_jiffies(usecs > 100000 ? usecs : 100000);
- HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%u", csr->expire, HZ);
-}
-
-
-static void add_host(struct hpsb_host *host)
-{
- struct csr1212_keyval *root;
- quadlet_t bus_info[CSR_BUS_INFO_SIZE];
-
- hpsb_register_addrspace(&csr_highlevel, host, &reg_ops,
- CSR_REGISTER_BASE,
- CSR_REGISTER_BASE + CSR_CONFIG_ROM);
- hpsb_register_addrspace(&csr_highlevel, host, &config_rom_ops,
- CSR_REGISTER_BASE + CSR_CONFIG_ROM,
- CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
- if (fcp) {
- hpsb_register_addrspace(&csr_highlevel, host, &fcp_ops,
- CSR_REGISTER_BASE + CSR_FCP_COMMAND,
- CSR_REGISTER_BASE + CSR_FCP_END);
- }
- hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
- CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
- CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
- hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
- CSR_REGISTER_BASE + CSR_SPEED_MAP,
- CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
-
- spin_lock_init(&host->csr.lock);
-
- host->csr.state = 0;
- host->csr.node_ids = 0;
- host->csr.split_timeout_hi = 0;
- host->csr.split_timeout_lo = 800 << 19;
- calculate_expire(&host->csr);
- host->csr.cycle_time = 0;
- host->csr.bus_time = 0;
- host->csr.bus_manager_id = 0x3f;
- host->csr.bandwidth_available = 4915;
- host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */
- host->csr.channels_available_lo = ~0;
- host->csr.broadcast_channel = 0x80000000 | 31;
-
- if (host->is_irm) {
- if (host->driver->hw_csr_reg) {
- host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
- }
- }
-
- if (host->csr.max_rec >= 9)
- host->csr.max_rom = 2;
- else if (host->csr.max_rec >= 5)
- host->csr.max_rom = 1;
- else
- host->csr.max_rom = 0;
-
- host->csr.generation = 2;
-
- bus_info[1] = IEEE1394_BUSID_MAGIC;
- bus_info[2] = cpu_to_be32((hpsb_disable_irm ? 0 : 1 << CSR_IRMC_SHIFT) |
- (1 << CSR_CMC_SHIFT) |
- (1 << CSR_ISC_SHIFT) |
- (0 << CSR_BMC_SHIFT) |
- (0 << CSR_PMC_SHIFT) |
- (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
- (host->csr.max_rec << CSR_MAX_REC_SHIFT) |
- (host->csr.max_rom << CSR_MAX_ROM_SHIFT) |
- (host->csr.generation << CSR_GENERATION_SHIFT) |
- host->csr.lnk_spd);
-
- bus_info[3] = cpu_to_be32(host->csr.guid_hi);
- bus_info[4] = cpu_to_be32(host->csr.guid_lo);
-
- /* The hardware copy of the bus info block will be set later when a
- * bus reset is issued. */
-
- csr1212_init_local_csr(host->csr.rom, bus_info, host->csr.max_rom);
-
- root = host->csr.rom->root_kv;
-
- if(csr1212_attach_keyval_to_directory(root, node_cap) != CSR1212_SUCCESS) {
- HPSB_ERR("Failed to attach Node Capabilities to root directory");
- }
-
- host->update_config_rom = 1;
-}
-
-static void remove_host(struct hpsb_host *host)
-{
- quadlet_t bus_info[CSR_BUS_INFO_SIZE];
-
- bus_info[1] = IEEE1394_BUSID_MAGIC;
- bus_info[2] = cpu_to_be32((0 << CSR_IRMC_SHIFT) |
- (0 << CSR_CMC_SHIFT) |
- (0 << CSR_ISC_SHIFT) |
- (0 << CSR_BMC_SHIFT) |
- (0 << CSR_PMC_SHIFT) |
- (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
- (host->csr.max_rec << CSR_MAX_REC_SHIFT) |
- (0 << CSR_MAX_ROM_SHIFT) |
- (0 << CSR_GENERATION_SHIFT) |
- host->csr.lnk_spd);
-
- bus_info[3] = cpu_to_be32(host->csr.guid_hi);
- bus_info[4] = cpu_to_be32(host->csr.guid_lo);
-
- csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, node_cap);
-
- csr1212_init_local_csr(host->csr.rom, bus_info, 0);
- host->update_config_rom = 1;
-}
-
-
-int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
- size_t buffersize, unsigned char rom_version)
-{
- unsigned long flags;
- int ret;
-
- HPSB_NOTICE("hpsb_update_config_rom() is deprecated");
-
- spin_lock_irqsave(&host->csr.lock, flags);
- if (rom_version != host->csr.generation)
- ret = -1;
- else if (buffersize > host->csr.rom->cache_head->size)
- ret = -2;
- else {
- /* Just overwrite the generated ConfigROM image with new data,
- * it can be regenerated later. */
- memcpy(host->csr.rom->cache_head->data, new_rom, buffersize);
- host->csr.rom->cache_head->len = buffersize;
-
- if (host->driver->set_hw_config_rom)
- host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
- /* Increment the generation number to keep some sort of sync
- * with the newer ConfigROM manipulation method. */
- host->csr.generation++;
- if (host->csr.generation > 0xf || host->csr.generation < 2)
- host->csr.generation = 2;
- ret=0;
- }
- spin_unlock_irqrestore(&host->csr.lock, flags);
- return ret;
-}
-
-
-/* Read topology / speed maps and configuration ROM */
-static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 fl)
-{
- unsigned long flags;
- int csraddr = addr - CSR_REGISTER_BASE;
- const char *src;
-
- spin_lock_irqsave(&host->csr.lock, flags);
-
- if (csraddr < CSR_SPEED_MAP) {
- src = ((char *)host->csr.topology_map) + csraddr
- - CSR_TOPOLOGY_MAP;
- } else {
- src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP;
- }
-
- memcpy(buffer, src, length);
- spin_unlock_irqrestore(&host->csr.lock, flags);
- return RCODE_COMPLETE;
-}
-
-
-#define out if (--length == 0) break
-
-static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
- u64 addr, size_t length, u16 flags)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- int oldcycle;
- quadlet_t ret;
-
- if ((csraddr | length) & 0x3)
- return RCODE_TYPE_ERROR;
-
- length /= 4;
-
- switch (csraddr) {
- case CSR_STATE_CLEAR:
- *(buf++) = cpu_to_be32(host->csr.state);
- out;
- case CSR_STATE_SET:
- *(buf++) = cpu_to_be32(host->csr.state);
- out;
- case CSR_NODE_IDS:
- *(buf++) = cpu_to_be32(host->csr.node_ids);
- out;
-
- case CSR_RESET_START:
- return RCODE_TYPE_ERROR;
-
- /* address gap - handled by default below */
-
- case CSR_SPLIT_TIMEOUT_HI:
- *(buf++) = cpu_to_be32(host->csr.split_timeout_hi);
- out;
- case CSR_SPLIT_TIMEOUT_LO:
- *(buf++) = cpu_to_be32(host->csr.split_timeout_lo);
- out;
-
- /* address gap */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_CYCLE_TIME:
- oldcycle = host->csr.cycle_time;
- host->csr.cycle_time =
- host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
-
- if (oldcycle > host->csr.cycle_time) {
- /* cycle time wrapped around */
- host->csr.bus_time += 1 << 7;
- }
- *(buf++) = cpu_to_be32(host->csr.cycle_time);
- out;
- case CSR_BUS_TIME:
- oldcycle = host->csr.cycle_time;
- host->csr.cycle_time =
- host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
-
- if (oldcycle > host->csr.cycle_time) {
- /* cycle time wrapped around */
- host->csr.bus_time += (1 << 7);
- }
- *(buf++) = cpu_to_be32(host->csr.bus_time
- | (host->csr.cycle_time >> 25));
- out;
-
- /* address gap */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_BUSY_TIMEOUT:
- /* not yet implemented */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_BUS_MANAGER_ID:
- if (host->driver->hw_csr_reg)
- ret = host->driver->hw_csr_reg(host, 0, 0, 0);
- else
- ret = host->csr.bus_manager_id;
-
- *(buf++) = cpu_to_be32(ret);
- out;
- case CSR_BANDWIDTH_AVAILABLE:
- if (host->driver->hw_csr_reg)
- ret = host->driver->hw_csr_reg(host, 1, 0, 0);
- else
- ret = host->csr.bandwidth_available;
-
- *(buf++) = cpu_to_be32(ret);
- out;
- case CSR_CHANNELS_AVAILABLE_HI:
- if (host->driver->hw_csr_reg)
- ret = host->driver->hw_csr_reg(host, 2, 0, 0);
- else
- ret = host->csr.channels_available_hi;
-
- *(buf++) = cpu_to_be32(ret);
- out;
- case CSR_CHANNELS_AVAILABLE_LO:
- if (host->driver->hw_csr_reg)
- ret = host->driver->hw_csr_reg(host, 3, 0, 0);
- else
- ret = host->csr.channels_available_lo;
-
- *(buf++) = cpu_to_be32(ret);
- out;
-
- case CSR_BROADCAST_CHANNEL:
- *(buf++) = cpu_to_be32(host->csr.broadcast_channel);
- out;
-
- /* address gap to end - fall through to default */
- default:
- return RCODE_ADDRESS_ERROR;
- }
-
- return RCODE_COMPLETE;
-}
-
-static int write_regs(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t *data, u64 addr, size_t length, u16 flags)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
-
- if ((csraddr | length) & 0x3)
- return RCODE_TYPE_ERROR;
-
- length /= 4;
-
- switch (csraddr) {
- case CSR_STATE_CLEAR:
- /* FIXME FIXME FIXME */
- printk("doh, someone wants to mess with state clear\n");
- out;
- case CSR_STATE_SET:
- printk("doh, someone wants to mess with state set\n");
- out;
-
- case CSR_NODE_IDS:
- host->csr.node_ids &= NODE_MASK << 16;
- host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
- host->node_id = host->csr.node_ids >> 16;
- host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6);
- out;
-
- case CSR_RESET_START:
- /* FIXME - perform command reset */
- out;
-
- /* address gap */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_SPLIT_TIMEOUT_HI:
- host->csr.split_timeout_hi =
- be32_to_cpu(*(data++)) & 0x00000007;
- calculate_expire(&host->csr);
- out;
- case CSR_SPLIT_TIMEOUT_LO:
- host->csr.split_timeout_lo =
- be32_to_cpu(*(data++)) & 0xfff80000;
- calculate_expire(&host->csr);
- out;
-
- /* address gap */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_CYCLE_TIME:
- /* should only be set by cycle start packet, automatically */
- host->csr.cycle_time = be32_to_cpu(*data);
- host->driver->devctl(host, SET_CYCLE_COUNTER,
- be32_to_cpu(*(data++)));
- out;
- case CSR_BUS_TIME:
- host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80;
- out;
-
- /* address gap */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_BUSY_TIMEOUT:
- /* not yet implemented */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_BUS_MANAGER_ID:
- case CSR_BANDWIDTH_AVAILABLE:
- case CSR_CHANNELS_AVAILABLE_HI:
- case CSR_CHANNELS_AVAILABLE_LO:
- /* these are not writable, only lockable */
- return RCODE_TYPE_ERROR;
-
- case CSR_BROADCAST_CHANNEL:
- /* only the valid bit can be written */
- host->csr.broadcast_channel = (host->csr.broadcast_channel & ~0x40000000)
- | (be32_to_cpu(*data) & 0x40000000);
- out;
-
- /* address gap to end - fall through */
- default:
- return RCODE_ADDRESS_ERROR;
- }
-
- return RCODE_COMPLETE;
-}
-
-#undef out
-
-
-static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- unsigned long flags;
- quadlet_t *regptr = NULL;
-
- if (csraddr & 0x3)
- return RCODE_TYPE_ERROR;
-
- if (csraddr < CSR_BUS_MANAGER_ID || csraddr > CSR_CHANNELS_AVAILABLE_LO
- || extcode != EXTCODE_COMPARE_SWAP)
- goto unsupported_lockreq;
-
- data = be32_to_cpu(data);
- arg = be32_to_cpu(arg);
-
- /* Is somebody releasing the broadcast_channel on us? */
- if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x1)) {
- /* Note: this is may not be the right way to handle
- * the problem, so we should look into the proper way
- * eventually. */
- HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
- "broadcast channel 31. Ignoring.",
- NODE_BUS_ARGS(host, nodeid));
-
- data &= ~0x1; /* keep broadcast channel allocated */
- }
-
- if (host->driver->hw_csr_reg) {
- quadlet_t old;
-
- old = host->driver->
- hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
- data, arg);
-
- *store = cpu_to_be32(old);
- return RCODE_COMPLETE;
- }
-
- spin_lock_irqsave(&host->csr.lock, flags);
-
- switch (csraddr) {
- case CSR_BUS_MANAGER_ID:
- regptr = &host->csr.bus_manager_id;
- *store = cpu_to_be32(*regptr);
- if (*regptr == arg)
- *regptr = data;
- break;
-
- case CSR_BANDWIDTH_AVAILABLE:
- {
- quadlet_t bandwidth;
- quadlet_t old;
- quadlet_t new;
-
- regptr = &host->csr.bandwidth_available;
- old = *regptr;
-
- /* bandwidth available algorithm adapted from IEEE 1394a-2000 spec */
- if (arg > 0x1fff) {
- *store = cpu_to_be32(old); /* change nothing */
- break;
- }
- data &= 0x1fff;
- if (arg >= data) {
- /* allocate bandwidth */
- bandwidth = arg - data;
- if (old >= bandwidth) {
- new = old - bandwidth;
- *store = cpu_to_be32(arg);
- *regptr = new;
- } else {
- *store = cpu_to_be32(old);
- }
- } else {
- /* deallocate bandwidth */
- bandwidth = data - arg;
- if (old + bandwidth < 0x2000) {
- new = old + bandwidth;
- *store = cpu_to_be32(arg);
- *regptr = new;
- } else {
- *store = cpu_to_be32(old);
- }
- }
- break;
- }
-
- case CSR_CHANNELS_AVAILABLE_HI:
- {
- /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
- quadlet_t affected_channels = arg ^ data;
-
- regptr = &host->csr.channels_available_hi;
-
- if ((arg & affected_channels) == (*regptr & affected_channels)) {
- *regptr ^= affected_channels;
- *store = cpu_to_be32(arg);
- } else {
- *store = cpu_to_be32(*regptr);
- }
-
- break;
- }
-
- case CSR_CHANNELS_AVAILABLE_LO:
- {
- /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
- quadlet_t affected_channels = arg ^ data;
-
- regptr = &host->csr.channels_available_lo;
-
- if ((arg & affected_channels) == (*regptr & affected_channels)) {
- *regptr ^= affected_channels;
- *store = cpu_to_be32(arg);
- } else {
- *store = cpu_to_be32(*regptr);
- }
- break;
- }
- }
-
- spin_unlock_irqrestore(&host->csr.lock, flags);
-
- return RCODE_COMPLETE;
-
- unsupported_lockreq:
- switch (csraddr) {
- case CSR_STATE_CLEAR:
- case CSR_STATE_SET:
- case CSR_RESET_START:
- case CSR_NODE_IDS:
- case CSR_SPLIT_TIMEOUT_HI:
- case CSR_SPLIT_TIMEOUT_LO:
- case CSR_CYCLE_TIME:
- case CSR_BUS_TIME:
- case CSR_BROADCAST_CHANNEL:
- return RCODE_TYPE_ERROR;
-
- case CSR_BUSY_TIMEOUT:
- /* not yet implemented - fall through */
- default:
- return RCODE_ADDRESS_ERROR;
- }
-}
-
-static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
- u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- unsigned long flags;
-
- data = be64_to_cpu(data);
- arg = be64_to_cpu(arg);
-
- if (csraddr & 0x3)
- return RCODE_TYPE_ERROR;
-
- if (csraddr != CSR_CHANNELS_AVAILABLE
- || extcode != EXTCODE_COMPARE_SWAP)
- goto unsupported_lock64req;
-
- /* Is somebody releasing the broadcast_channel on us? */
- if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x100000000ULL)) {
- /* Note: this is may not be the right way to handle
- * the problem, so we should look into the proper way
- * eventually. */
- HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
- "broadcast channel 31. Ignoring.",
- NODE_BUS_ARGS(host, nodeid));
-
- data &= ~0x100000000ULL; /* keep broadcast channel allocated */
- }
-
- if (host->driver->hw_csr_reg) {
- quadlet_t data_hi, data_lo;
- quadlet_t arg_hi, arg_lo;
- quadlet_t old_hi, old_lo;
-
- data_hi = data >> 32;
- data_lo = data & 0xFFFFFFFF;
- arg_hi = arg >> 32;
- arg_lo = arg & 0xFFFFFFFF;
-
- old_hi = host->driver->hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
- data_hi, arg_hi);
-
- old_lo = host->driver->hw_csr_reg(host, ((csraddr + 4) - CSR_BUS_MANAGER_ID) >> 2,
- data_lo, arg_lo);
-
- *store = cpu_to_be64(((octlet_t)old_hi << 32) | old_lo);
- } else {
- octlet_t old;
- octlet_t affected_channels = arg ^ data;
-
- spin_lock_irqsave(&host->csr.lock, flags);
-
- old = ((octlet_t)host->csr.channels_available_hi << 32) | host->csr.channels_available_lo;
-
- if ((arg & affected_channels) == (old & affected_channels)) {
- host->csr.channels_available_hi ^= (affected_channels >> 32);
- host->csr.channels_available_lo ^= (affected_channels & 0xffffffff);
- *store = cpu_to_be64(arg);
- } else {
- *store = cpu_to_be64(old);
- }
-
- spin_unlock_irqrestore(&host->csr.lock, flags);
- }
-
- /* Is somebody erroneously releasing the broadcast_channel on us? */
- if (host->csr.channels_available_hi & 0x1)
- host->csr.channels_available_hi &= ~0x1;
-
- return RCODE_COMPLETE;
-
- unsupported_lock64req:
- switch (csraddr) {
- case CSR_STATE_CLEAR:
- case CSR_STATE_SET:
- case CSR_RESET_START:
- case CSR_NODE_IDS:
- case CSR_SPLIT_TIMEOUT_HI:
- case CSR_SPLIT_TIMEOUT_LO:
- case CSR_CYCLE_TIME:
- case CSR_BUS_TIME:
- case CSR_BUS_MANAGER_ID:
- case CSR_BROADCAST_CHANNEL:
- case CSR_BUSY_TIMEOUT:
- case CSR_BANDWIDTH_AVAILABLE:
- return RCODE_TYPE_ERROR;
-
- default:
- return RCODE_ADDRESS_ERROR;
- }
-}
-
-static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
- quadlet_t *data, u64 addr, size_t length, u16 flags)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
-
- if (length > 512)
- return RCODE_TYPE_ERROR;
-
- switch (csraddr) {
- case CSR_FCP_COMMAND:
- highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length);
- break;
- case CSR_FCP_RESPONSE:
- highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length);
- break;
- default:
- return RCODE_TYPE_ERROR;
- }
-
- return RCODE_COMPLETE;
-}
-
-static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 fl)
-{
- u32 offset = addr - CSR1212_REGISTER_SPACE_BASE;
-
- if (csr1212_read(host->csr.rom, offset, buffer, length) == CSR1212_SUCCESS)
- return RCODE_COMPLETE;
- else
- return RCODE_ADDRESS_ERROR;
-}
-
-static u64 allocate_addr_range(u64 size, u32 alignment, void *__host)
-{
- struct hpsb_host *host = (struct hpsb_host*)__host;
-
- return hpsb_allocate_and_register_addrspace(&csr_highlevel,
- host,
- &config_rom_ops,
- size, alignment,
- CSR1212_UNITS_SPACE_BASE,
- CSR1212_UNITS_SPACE_END);
-}
-
-static void release_addr_range(u64 addr, void *__host)
-{
- struct hpsb_host *host = (struct hpsb_host*)__host;
- hpsb_unregister_addrspace(&csr_highlevel, host, addr);
-}
-
-
-int init_csr(void)
-{
- node_cap = csr1212_new_immediate(CSR1212_KV_ID_NODE_CAPABILITIES, 0x0083c0);
- if (!node_cap) {
- HPSB_ERR("Failed to allocate memory for Node Capabilties ConfigROM entry!");
- return -ENOMEM;
- }
-
- hpsb_register_highlevel(&csr_highlevel);
-
- return 0;
-}
-
-void cleanup_csr(void)
-{
- if (node_cap)
- csr1212_release_keyval(node_cap);
- hpsb_unregister_highlevel(&csr_highlevel);
-}
diff --git a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h
deleted file mode 100644
index 90fb3f2192c3..000000000000
--- a/drivers/ieee1394/csr.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef _IEEE1394_CSR_H
-#define _IEEE1394_CSR_H
-
-#include <linux/spinlock_types.h>
-
-#include "csr1212.h"
-#include "ieee1394_types.h"
-
-#define CSR_REGISTER_BASE 0xfffff0000000ULL
-
-/* register offsets relative to CSR_REGISTER_BASE */
-#define CSR_STATE_CLEAR 0x0
-#define CSR_STATE_SET 0x4
-#define CSR_NODE_IDS 0x8
-#define CSR_RESET_START 0xc
-#define CSR_SPLIT_TIMEOUT_HI 0x18
-#define CSR_SPLIT_TIMEOUT_LO 0x1c
-#define CSR_CYCLE_TIME 0x200
-#define CSR_BUS_TIME 0x204
-#define CSR_BUSY_TIMEOUT 0x210
-#define CSR_BUS_MANAGER_ID 0x21c
-#define CSR_BANDWIDTH_AVAILABLE 0x220
-#define CSR_CHANNELS_AVAILABLE 0x224
-#define CSR_CHANNELS_AVAILABLE_HI 0x224
-#define CSR_CHANNELS_AVAILABLE_LO 0x228
-#define CSR_BROADCAST_CHANNEL 0x234
-#define CSR_CONFIG_ROM 0x400
-#define CSR_CONFIG_ROM_END 0x800
-#define CSR_FCP_COMMAND 0xB00
-#define CSR_FCP_RESPONSE 0xD00
-#define CSR_FCP_END 0xF00
-#define CSR_TOPOLOGY_MAP 0x1000
-#define CSR_TOPOLOGY_MAP_END 0x1400
-#define CSR_SPEED_MAP 0x2000
-#define CSR_SPEED_MAP_END 0x3000
-
-/* IEEE 1394 bus specific Configuration ROM Key IDs */
-#define IEEE1394_KV_ID_POWER_REQUIREMENTS (0x30)
-
-/* IEEE 1394 Bus Information Block specifics */
-#define CSR_BUS_INFO_SIZE (5 * sizeof(quadlet_t))
-
-#define CSR_IRMC_SHIFT 31
-#define CSR_CMC_SHIFT 30
-#define CSR_ISC_SHIFT 29
-#define CSR_BMC_SHIFT 28
-#define CSR_PMC_SHIFT 27
-#define CSR_CYC_CLK_ACC_SHIFT 16
-#define CSR_MAX_REC_SHIFT 12
-#define CSR_MAX_ROM_SHIFT 8
-#define CSR_GENERATION_SHIFT 4
-
-static inline void csr_set_bus_info_generation(struct csr1212_csr *csr, u8 gen)
-{
- csr->bus_info_data[2] &= ~cpu_to_be32(0xf << CSR_GENERATION_SHIFT);
- csr->bus_info_data[2] |= cpu_to_be32((u32)gen << CSR_GENERATION_SHIFT);
-}
-
-struct csr_control {
- spinlock_t lock;
-
- quadlet_t state;
- quadlet_t node_ids;
- quadlet_t split_timeout_hi, split_timeout_lo;
- unsigned long expire; /* Calculated from split_timeout */
- quadlet_t cycle_time;
- quadlet_t bus_time;
- quadlet_t bus_manager_id;
- quadlet_t bandwidth_available;
- quadlet_t channels_available_hi, channels_available_lo;
- quadlet_t broadcast_channel;
-
- /* Bus Info */
- quadlet_t guid_hi, guid_lo;
- u8 cyc_clk_acc;
- u8 max_rec;
- u8 max_rom;
- u8 generation; /* Only use values between 0x2 and 0xf */
- u8 lnk_spd;
-
- unsigned long gen_timestamp[16];
-
- struct csr1212_csr *rom;
-
- quadlet_t topology_map[256];
- quadlet_t speed_map[1024];
-};
-
-extern struct csr1212_bus_ops csr_bus_ops;
-
-int init_csr(void);
-void cleanup_csr(void);
-
-/* hpsb_update_config_rom() is deprecated */
-struct hpsb_host;
-int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
- size_t size, unsigned char rom_version);
-
-#endif /* _IEEE1394_CSR_H */
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
deleted file mode 100644
index e76cac64c533..000000000000
--- a/drivers/ieee1394/csr1212.c
+++ /dev/null
@@ -1,1467 +0,0 @@
-/*
- * csr1212.c -- IEEE 1212 Control and Status Register support for Linux
- *
- * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
- * Steve Kinneberg <kinnebergsteve@acmsystems.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-
-/* TODO List:
- * - Verify interface consistency: i.e., public functions that take a size
- * parameter expect size to be in bytes.
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/kmemcheck.h>
-#include <linux/string.h>
-#include <asm/bug.h>
-#include <asm/byteorder.h>
-
-#include "csr1212.h"
-
-
-/* Permitted key type for each key id */
-#define __I (1 << CSR1212_KV_TYPE_IMMEDIATE)
-#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
-#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
-#define __L (1 << CSR1212_KV_TYPE_LEAF)
-static const u8 csr1212_key_id_type_map[0x30] = {
- __C, /* used by Apple iSight */
- __D | __L, /* Descriptor */
- __I | __D | __L, /* Bus_Dependent_Info */
- __I | __D | __L, /* Vendor */
- __I, /* Hardware_Version */
- 0, 0, /* Reserved */
- __D | __L | __I, /* Module */
- __I, 0, 0, 0, /* used by Apple iSight, Reserved */
- __I, /* Node_Capabilities */
- __L, /* EUI_64 */
- 0, 0, 0, /* Reserved */
- __D, /* Unit */
- __I, /* Specifier_ID */
- __I, /* Version */
- __I | __C | __D | __L, /* Dependent_Info */
- __L, /* Unit_Location */
- 0, /* Reserved */
- __I, /* Model */
- __D, /* Instance */
- __L, /* Keyword */
- __D, /* Feature */
- __L, /* Extended_ROM */
- __I, /* Extended_Key_Specifier_ID */
- __I, /* Extended_Key */
- __I | __C | __D | __L, /* Extended_Data */
- __L, /* Modifiable_Descriptor */
- __I, /* Directory_ID */
- __I, /* Revision */
-};
-#undef __I
-#undef __C
-#undef __D
-#undef __L
-
-
-#define quads_to_bytes(_q) ((_q) * sizeof(u32))
-#define bytes_to_quads(_b) DIV_ROUND_UP(_b, sizeof(u32))
-
-static void free_keyval(struct csr1212_keyval *kv)
-{
- if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
- (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
- CSR1212_FREE(kv->value.leaf.data);
-
- CSR1212_FREE(kv);
-}
-
-static u16 csr1212_crc16(const u32 *buffer, size_t length)
-{
- int shift;
- u32 data;
- u16 sum, crc = 0;
-
- for (; length; length--) {
- data = be32_to_cpu(*buffer);
- buffer++;
- for (shift = 28; shift >= 0; shift -= 4 ) {
- sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
- crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
- }
- crc &= 0xffff;
- }
-
- return cpu_to_be16(crc);
-}
-
-/* Microsoft computes the CRC with the bytes in reverse order. */
-static u16 csr1212_msft_crc16(const u32 *buffer, size_t length)
-{
- int shift;
- u32 data;
- u16 sum, crc = 0;
-
- for (; length; length--) {
- data = le32_to_cpu(*buffer);
- buffer++;
- for (shift = 28; shift >= 0; shift -= 4 ) {
- sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
- crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
- }
- crc &= 0xffff;
- }
-
- return cpu_to_be16(crc);
-}
-
-static struct csr1212_dentry *
-csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv)
-{
- struct csr1212_dentry *pos;
-
- for (pos = dir->value.directory.dentries_head;
- pos != NULL; pos = pos->next)
- if (pos->kv == kv)
- return pos;
- return NULL;
-}
-
-static struct csr1212_keyval *
-csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
-{
- struct csr1212_keyval *kv;
-
- for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next)
- if (kv->offset == offset)
- return kv;
- return NULL;
-}
-
-
-/* Creation Routines */
-
-struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
- size_t bus_info_size, void *private)
-{
- struct csr1212_csr *csr;
-
- csr = CSR1212_MALLOC(sizeof(*csr));
- if (!csr)
- return NULL;
-
- csr->cache_head =
- csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET,
- CSR1212_CONFIG_ROM_SPACE_SIZE);
- if (!csr->cache_head) {
- CSR1212_FREE(csr);
- return NULL;
- }
-
- /* The keyval key id is not used for the root node, but a valid key id
- * that can be used for a directory needs to be passed to
- * csr1212_new_directory(). */
- csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
- if (!csr->root_kv) {
- CSR1212_FREE(csr->cache_head);
- CSR1212_FREE(csr);
- return NULL;
- }
-
- csr->bus_info_data = csr->cache_head->data;
- csr->bus_info_len = bus_info_size;
- csr->crc_len = bus_info_size;
- csr->ops = ops;
- csr->private = private;
- csr->cache_tail = csr->cache_head;
-
- return csr;
-}
-
-void csr1212_init_local_csr(struct csr1212_csr *csr,
- const u32 *bus_info_data, int max_rom)
-{
- static const int mr_map[] = { 4, 64, 1024, 0 };
-
- BUG_ON(max_rom & ~0x3);
- csr->max_rom = mr_map[max_rom];
- memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
-}
-
-static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
-{
- struct csr1212_keyval *kv;
-
- if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0))
- return NULL;
-
- kv = CSR1212_MALLOC(sizeof(*kv));
- if (!kv)
- return NULL;
-
- atomic_set(&kv->refcnt, 1);
- kv->key.type = type;
- kv->key.id = key;
- kv->associate = NULL;
- kv->next = NULL;
- kv->prev = NULL;
- kv->offset = 0;
- kv->valid = 0;
- return kv;
-}
-
-struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
-{
- struct csr1212_keyval *kv;
-
- kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
- if (!kv)
- return NULL;
-
- kv->value.immediate = value;
- kv->valid = 1;
- return kv;
-}
-
-static struct csr1212_keyval *
-csr1212_new_leaf(u8 key, const void *data, size_t data_len)
-{
- struct csr1212_keyval *kv;
-
- kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
- if (!kv)
- return NULL;
-
- if (data_len > 0) {
- kv->value.leaf.data = CSR1212_MALLOC(data_len);
- if (!kv->value.leaf.data) {
- CSR1212_FREE(kv);
- return NULL;
- }
-
- if (data)
- memcpy(kv->value.leaf.data, data, data_len);
- } else {
- kv->value.leaf.data = NULL;
- }
-
- kv->value.leaf.len = bytes_to_quads(data_len);
- kv->offset = 0;
- kv->valid = 1;
-
- return kv;
-}
-
-static struct csr1212_keyval *
-csr1212_new_csr_offset(u8 key, u32 csr_offset)
-{
- struct csr1212_keyval *kv;
-
- kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
- if (!kv)
- return NULL;
-
- kv->value.csr_offset = csr_offset;
-
- kv->offset = 0;
- kv->valid = 1;
- return kv;
-}
-
-struct csr1212_keyval *csr1212_new_directory(u8 key)
-{
- struct csr1212_keyval *kv;
-
- kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
- if (!kv)
- return NULL;
-
- kv->value.directory.len = 0;
- kv->offset = 0;
- kv->value.directory.dentries_head = NULL;
- kv->value.directory.dentries_tail = NULL;
- kv->valid = 1;
- return kv;
-}
-
-void csr1212_associate_keyval(struct csr1212_keyval *kv,
- struct csr1212_keyval *associate)
-{
- BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
- (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
- associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
- associate->key.id < 0x30) ||
- (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) ||
- (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) ||
- (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
- kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) ||
- (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
- kv->key.id != CSR1212_KV_ID_EXTENDED_KEY));
-
- if (kv->associate)
- csr1212_release_keyval(kv->associate);
-
- csr1212_keep_keyval(associate);
- kv->associate = associate;
-}
-
-static int __csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv,
- bool keep_keyval)
-{
- struct csr1212_dentry *dentry;
-
- BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY);
-
- dentry = CSR1212_MALLOC(sizeof(*dentry));
- if (!dentry)
- return -ENOMEM;
-
- if (keep_keyval)
- csr1212_keep_keyval(kv);
- dentry->kv = kv;
-
- dentry->next = NULL;
- dentry->prev = dir->value.directory.dentries_tail;
-
- if (!dir->value.directory.dentries_head)
- dir->value.directory.dentries_head = dentry;
-
- if (dir->value.directory.dentries_tail)
- dir->value.directory.dentries_tail->next = dentry;
- dir->value.directory.dentries_tail = dentry;
-
- return CSR1212_SUCCESS;
-}
-
-int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv)
-{
- return __csr1212_attach_keyval_to_directory(dir, kv, true);
-}
-
-#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
- (&((kv)->value.leaf.data[1]))
-
-#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
- ((kv)->value.leaf.data[0] = \
- cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
- ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
-#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
- ((kv)->value.leaf.data[0] = \
- cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
- CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
- ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
-
-static struct csr1212_keyval *
-csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
- const void *data, size_t data_len)
-{
- struct csr1212_keyval *kv;
-
- kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL,
- data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD);
- if (!kv)
- return NULL;
-
- kmemcheck_annotate_variable(kv->value.leaf.data[0]);
- CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
- CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
-
- if (data)
- memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
-
- return kv;
-}
-
-/* Check if string conforms to minimal ASCII as per IEEE 1212 clause 7.4 */
-static int csr1212_check_minimal_ascii(const char *s)
-{
- static const char minimal_ascii_table[] = {
- /* 1 2 4 8 16 32 64 128 */
- 128, /* --, --, --, --, --, --, --, 07, */
- 4 + 16 + 32, /* --, --, 0a, --, 0C, 0D, --, --, */
- 0, /* --, --, --, --, --, --, --, --, */
- 0, /* --, --, --, --, --, --, --, --, */
- 255 - 8 - 16, /* 20, 21, 22, --, --, 25, 26, 27, */
- 255, /* 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, */
- 255, /* 30, 31, 32, 33, 34, 35, 36, 37, */
- 255, /* 38, 39, 3a, 3b, 3c, 3d, 3e, 3f, */
- 255, /* 40, 41, 42, 43, 44, 45, 46, 47, */
- 255, /* 48, 49, 4a, 4b, 4c, 4d, 4e, 4f, */
- 255, /* 50, 51, 52, 53, 54, 55, 56, 57, */
- 1 + 2 + 4 + 128, /* 58, 59, 5a, --, --, --, --, 5f, */
- 255 - 1, /* --, 61, 62, 63, 64, 65, 66, 67, */
- 255, /* 68, 69, 6a, 6b, 6c, 6d, 6e, 6f, */
- 255, /* 70, 71, 72, 73, 74, 75, 76, 77, */
- 1 + 2 + 4, /* 78, 79, 7a, --, --, --, --, --, */
- };
- int i, j;
-
- for (; *s; s++) {
- i = *s >> 3; /* i = *s / 8; */
- j = 1 << (*s & 3); /* j = 1 << (*s % 8); */
-
- if (i >= ARRAY_SIZE(minimal_ascii_table) ||
- !(minimal_ascii_table[i] & j))
- return -EINVAL;
- }
- return 0;
-}
-
-/* IEEE 1212 clause 7.5.4.1 textual descriptors (English, minimal ASCII) */
-struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
-{
- struct csr1212_keyval *kv;
- u32 *text;
- size_t str_len, quads;
-
- if (!s || !*s || csr1212_check_minimal_ascii(s))
- return NULL;
-
- str_len = strlen(s);
- quads = bytes_to_quads(str_len);
- kv = csr1212_new_descriptor_leaf(0, 0, NULL, quads_to_bytes(quads) +
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
- if (!kv)
- return NULL;
-
- kv->value.leaf.data[1] = 0; /* width, character_set, language */
- text = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
- text[quads - 1] = 0; /* padding */
- memcpy(text, s, str_len);
-
- return kv;
-}
-
-
-/* Destruction Routines */
-
-void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv)
-{
- struct csr1212_dentry *dentry;
-
- if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
- return;
-
- dentry = csr1212_find_keyval(dir, kv);
-
- if (!dentry)
- return;
-
- if (dentry->prev)
- dentry->prev->next = dentry->next;
- if (dentry->next)
- dentry->next->prev = dentry->prev;
- if (dir->value.directory.dentries_head == dentry)
- dir->value.directory.dentries_head = dentry->next;
- if (dir->value.directory.dentries_tail == dentry)
- dir->value.directory.dentries_tail = dentry->prev;
-
- CSR1212_FREE(dentry);
-
- csr1212_release_keyval(kv);
-}
-
-/* This function is used to free the memory taken by a keyval. If the given
- * keyval is a directory type, then any keyvals contained in that directory
- * will be destroyed as well if noone holds a reference on them. By means of
- * list manipulation, this routine will descend a directory structure in a
- * non-recursive manner. */
-void csr1212_release_keyval(struct csr1212_keyval *kv)
-{
- struct csr1212_keyval *k, *a;
- struct csr1212_dentry dentry;
- struct csr1212_dentry *head, *tail;
-
- if (!atomic_dec_and_test(&kv->refcnt))
- return;
-
- dentry.kv = kv;
- dentry.next = NULL;
- dentry.prev = NULL;
-
- head = &dentry;
- tail = head;
-
- while (head) {
- k = head->kv;
-
- while (k) {
- /* must not dec_and_test kv->refcnt again */
- if (k != kv && !atomic_dec_and_test(&k->refcnt))
- break;
-
- a = k->associate;
-
- if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
- /* If the current entry is a directory, move all
- * the entries to the destruction list. */
- if (k->value.directory.dentries_head) {
- tail->next =
- k->value.directory.dentries_head;
- k->value.directory.dentries_head->prev =
- tail;
- tail = k->value.directory.dentries_tail;
- }
- }
- free_keyval(k);
- k = a;
- }
-
- head = head->next;
- if (head) {
- if (head->prev && head->prev != &dentry)
- CSR1212_FREE(head->prev);
- head->prev = NULL;
- } else if (tail != &dentry) {
- CSR1212_FREE(tail);
- }
- }
-}
-
-void csr1212_destroy_csr(struct csr1212_csr *csr)
-{
- struct csr1212_csr_rom_cache *c, *oc;
- struct csr1212_cache_region *cr, *ocr;
-
- csr1212_release_keyval(csr->root_kv);
-
- c = csr->cache_head;
- while (c) {
- oc = c;
- cr = c->filled_head;
- while (cr) {
- ocr = cr;
- cr = cr->next;
- CSR1212_FREE(ocr);
- }
- c = c->next;
- CSR1212_FREE(oc);
- }
-
- CSR1212_FREE(csr);
-}
-
-
-/* CSR Image Creation */
-
-static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
-{
- struct csr1212_csr_rom_cache *cache;
- u64 csr_addr;
-
- BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range ||
- !csr->ops->release_addr || csr->max_rom < 1);
-
- /* ROM size must be a multiple of csr->max_rom */
- romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
-
- csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom,
- csr->private);
- if (csr_addr == CSR1212_INVALID_ADDR_SPACE)
- return -ENOMEM;
-
- if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
- /* Invalid address returned from allocate_addr_range(). */
- csr->ops->release_addr(csr_addr, csr->private);
- return -ENOMEM;
- }
-
- cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE,
- romsize);
- if (!cache) {
- csr->ops->release_addr(csr_addr, csr->private);
- return -ENOMEM;
- }
-
- cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF,
- CSR1212_KV_ID_EXTENDED_ROM);
- if (!cache->ext_rom) {
- csr->ops->release_addr(csr_addr, csr->private);
- CSR1212_FREE(cache);
- return -ENOMEM;
- }
-
- if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) !=
- CSR1212_SUCCESS) {
- csr1212_release_keyval(cache->ext_rom);
- csr->ops->release_addr(csr_addr, csr->private);
- CSR1212_FREE(cache);
- return -ENOMEM;
- }
- cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
- cache->ext_rom->value.leaf.len = -1;
- cache->ext_rom->value.leaf.data = cache->data;
-
- /* Add cache to tail of cache list */
- cache->prev = csr->cache_tail;
- csr->cache_tail->next = cache;
- csr->cache_tail = cache;
- return CSR1212_SUCCESS;
-}
-
-static void csr1212_remove_cache(struct csr1212_csr *csr,
- struct csr1212_csr_rom_cache *cache)
-{
- if (csr->cache_head == cache)
- csr->cache_head = cache->next;
- if (csr->cache_tail == cache)
- csr->cache_tail = cache->prev;
-
- if (cache->prev)
- cache->prev->next = cache->next;
- if (cache->next)
- cache->next->prev = cache->prev;
-
- if (cache->ext_rom) {
- csr1212_detach_keyval_from_directory(csr->root_kv,
- cache->ext_rom);
- csr1212_release_keyval(cache->ext_rom);
- }
-
- CSR1212_FREE(cache);
-}
-
-static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
- struct csr1212_keyval **layout_tail)
-{
- struct csr1212_dentry *dentry;
- struct csr1212_keyval *dkv;
- struct csr1212_keyval *last_extkey_spec = NULL;
- struct csr1212_keyval *last_extkey = NULL;
- int num_entries = 0;
-
- for (dentry = dir->value.directory.dentries_head; dentry;
- dentry = dentry->next) {
- for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
- /* Special Case: Extended Key Specifier_ID */
- if (dkv->key.id ==
- CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
- if (last_extkey_spec == NULL)
- last_extkey_spec = dkv;
- else if (dkv->value.immediate !=
- last_extkey_spec->value.immediate)
- last_extkey_spec = dkv;
- else
- continue;
- /* Special Case: Extended Key */
- } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
- if (last_extkey == NULL)
- last_extkey = dkv;
- else if (dkv->value.immediate !=
- last_extkey->value.immediate)
- last_extkey = dkv;
- else
- continue;
- }
-
- num_entries += 1;
-
- switch (dkv->key.type) {
- default:
- case CSR1212_KV_TYPE_IMMEDIATE:
- case CSR1212_KV_TYPE_CSR_OFFSET:
- break;
- case CSR1212_KV_TYPE_LEAF:
- case CSR1212_KV_TYPE_DIRECTORY:
- /* Remove from list */
- if (dkv->prev && (dkv->prev->next == dkv))
- dkv->prev->next = dkv->next;
- if (dkv->next && (dkv->next->prev == dkv))
- dkv->next->prev = dkv->prev;
- //if (dkv == *layout_tail)
- // *layout_tail = dkv->prev;
-
- /* Special case: Extended ROM leafs */
- if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
- dkv->value.leaf.len = -1;
- /* Don't add Extended ROM leafs in the
- * layout list, they are handled
- * differently. */
- break;
- }
-
- /* Add to tail of list */
- dkv->next = NULL;
- dkv->prev = *layout_tail;
- (*layout_tail)->next = dkv;
- *layout_tail = dkv;
- break;
- }
- }
- }
- return num_entries;
-}
-
-static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
-{
- struct csr1212_keyval *ltail = kv;
- size_t agg_size = 0;
-
- while (kv) {
- switch (kv->key.type) {
- case CSR1212_KV_TYPE_LEAF:
- /* Add 1 quadlet for crc/len field */
- agg_size += kv->value.leaf.len + 1;
- break;
-
- case CSR1212_KV_TYPE_DIRECTORY:
- kv->value.directory.len =
- csr1212_generate_layout_subdir(kv, &ltail);
- /* Add 1 quadlet for crc/len field */
- agg_size += kv->value.directory.len + 1;
- break;
- }
- kv = kv->next;
- }
- return quads_to_bytes(agg_size);
-}
-
-static struct csr1212_keyval *
-csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
- struct csr1212_keyval *start_kv, int start_pos)
-{
- struct csr1212_keyval *kv = start_kv;
- struct csr1212_keyval *okv = start_kv;
- int pos = start_pos;
- int kv_len = 0, okv_len = 0;
-
- cache->layout_head = kv;
-
- while (kv && pos < cache->size) {
- /* Special case: Extended ROM leafs */
- if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
- kv->offset = cache->offset + pos;
-
- switch (kv->key.type) {
- case CSR1212_KV_TYPE_LEAF:
- kv_len = kv->value.leaf.len;
- break;
-
- case CSR1212_KV_TYPE_DIRECTORY:
- kv_len = kv->value.directory.len;
- break;
-
- default:
- /* Should never get here */
- WARN_ON(1);
- break;
- }
-
- pos += quads_to_bytes(kv_len + 1);
-
- if (pos <= cache->size) {
- okv = kv;
- okv_len = kv_len;
- kv = kv->next;
- }
- }
-
- cache->layout_tail = okv;
- cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1);
-
- return kv;
-}
-
-#define CSR1212_KV_KEY_SHIFT 24
-#define CSR1212_KV_KEY_TYPE_SHIFT 6
-#define CSR1212_KV_KEY_ID_MASK 0x3f
-#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* after shift */
-
-static void
-csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
-{
- struct csr1212_dentry *dentry;
- struct csr1212_keyval *last_extkey_spec = NULL;
- struct csr1212_keyval *last_extkey = NULL;
- int index = 0;
-
- for (dentry = dir->value.directory.dentries_head;
- dentry;
- dentry = dentry->next) {
- struct csr1212_keyval *a;
-
- for (a = dentry->kv; a; a = a->associate) {
- u32 value = 0;
-
- /* Special Case: Extended Key Specifier_ID */
- if (a->key.id ==
- CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
- if (last_extkey_spec == NULL)
- last_extkey_spec = a;
- else if (a->value.immediate !=
- last_extkey_spec->value.immediate)
- last_extkey_spec = a;
- else
- continue;
-
- /* Special Case: Extended Key */
- } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
- if (last_extkey == NULL)
- last_extkey = a;
- else if (a->value.immediate !=
- last_extkey->value.immediate)
- last_extkey = a;
- else
- continue;
- }
-
- switch (a->key.type) {
- case CSR1212_KV_TYPE_IMMEDIATE:
- value = a->value.immediate;
- break;
- case CSR1212_KV_TYPE_CSR_OFFSET:
- value = a->value.csr_offset;
- break;
- case CSR1212_KV_TYPE_LEAF:
- value = a->offset;
- value -= dir->offset + quads_to_bytes(1+index);
- value = bytes_to_quads(value);
- break;
- case CSR1212_KV_TYPE_DIRECTORY:
- value = a->offset;
- value -= dir->offset + quads_to_bytes(1+index);
- value = bytes_to_quads(value);
- break;
- default:
- /* Should never get here */
- WARN_ON(1);
- break;
- }
-
- value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) <<
- CSR1212_KV_KEY_SHIFT;
- value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
- (CSR1212_KV_KEY_SHIFT +
- CSR1212_KV_KEY_TYPE_SHIFT);
- data_buffer[index] = cpu_to_be32(value);
- index++;
- }
- }
-}
-
-struct csr1212_keyval_img {
- u16 length;
- u16 crc;
-
- /* Must be last */
- u32 data[0]; /* older gcc can't handle [] which is standard */
-};
-
-static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
-{
- struct csr1212_keyval *kv, *nkv;
- struct csr1212_keyval_img *kvi;
-
- for (kv = cache->layout_head;
- kv != cache->layout_tail->next;
- kv = nkv) {
- kvi = (struct csr1212_keyval_img *)(cache->data +
- bytes_to_quads(kv->offset - cache->offset));
- switch (kv->key.type) {
- default:
- case CSR1212_KV_TYPE_IMMEDIATE:
- case CSR1212_KV_TYPE_CSR_OFFSET:
- /* Should never get here */
- WARN_ON(1);
- break;
-
- case CSR1212_KV_TYPE_LEAF:
- /* Don't copy over Extended ROM areas, they are
- * already filled out! */
- if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
- memcpy(kvi->data, kv->value.leaf.data,
- quads_to_bytes(kv->value.leaf.len));
-
- kvi->length = cpu_to_be16(kv->value.leaf.len);
- kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
- break;
-
- case CSR1212_KV_TYPE_DIRECTORY:
- csr1212_generate_tree_subdir(kv, kvi->data);
-
- kvi->length = cpu_to_be16(kv->value.directory.len);
- kvi->crc = csr1212_crc16(kvi->data,
- kv->value.directory.len);
- break;
- }
-
- nkv = kv->next;
- if (kv->prev)
- kv->prev->next = NULL;
- if (kv->next)
- kv->next->prev = NULL;
- kv->prev = NULL;
- kv->next = NULL;
- }
-}
-
-/* This size is arbitrarily chosen.
- * The struct overhead is subtracted for more economic allocations. */
-#define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache))
-
-int csr1212_generate_csr_image(struct csr1212_csr *csr)
-{
- struct csr1212_bus_info_block_img *bi;
- struct csr1212_csr_rom_cache *cache;
- struct csr1212_keyval *kv;
- size_t agg_size;
- int ret;
- int init_offset;
-
- BUG_ON(!csr);
-
- cache = csr->cache_head;
-
- bi = (struct csr1212_bus_info_block_img*)cache->data;
-
- bi->length = bytes_to_quads(csr->bus_info_len) - 1;
- bi->crc_length = bi->length;
- bi->crc = csr1212_crc16(bi->data, bi->crc_length);
-
- csr->root_kv->next = NULL;
- csr->root_kv->prev = NULL;
-
- agg_size = csr1212_generate_layout_order(csr->root_kv);
-
- init_offset = csr->bus_info_len;
-
- for (kv = csr->root_kv, cache = csr->cache_head;
- kv;
- cache = cache->next) {
- if (!cache) {
- /* Estimate approximate number of additional cache
- * regions needed (it assumes that the cache holding
- * the first 1K Config ROM space always exists). */
- int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
- (2 * sizeof(u32))) + 1;
-
- /* Add additional cache regions, extras will be
- * removed later */
- for (; est_c; est_c--) {
- ret = csr1212_append_new_cache(csr,
- CSR1212_EXTENDED_ROM_SIZE);
- if (ret != CSR1212_SUCCESS)
- return ret;
- }
- /* Need to re-layout for additional cache regions */
- agg_size = csr1212_generate_layout_order(csr->root_kv);
- kv = csr->root_kv;
- cache = csr->cache_head;
- init_offset = csr->bus_info_len;
- }
- kv = csr1212_generate_positions(cache, kv, init_offset);
- agg_size -= cache->len;
- init_offset = sizeof(u32);
- }
-
- /* Remove unused, excess cache regions */
- while (cache) {
- struct csr1212_csr_rom_cache *oc = cache;
-
- cache = cache->next;
- csr1212_remove_cache(csr, oc);
- }
-
- /* Go through the list backward so that when done, the correct CRC
- * will be calculated for the Extended ROM areas. */
- for (cache = csr->cache_tail; cache; cache = cache->prev) {
- /* Only Extended ROM caches should have this set. */
- if (cache->ext_rom) {
- int leaf_size;
-
- /* Make sure the Extended ROM leaf is a multiple of
- * max_rom in size. */
- BUG_ON(csr->max_rom < 1);
- leaf_size = (cache->len + (csr->max_rom - 1)) &
- ~(csr->max_rom - 1);
-
- /* Zero out the unused ROM region */
- memset(cache->data + bytes_to_quads(cache->len), 0x00,
- leaf_size - cache->len);
-
- /* Subtract leaf header */
- leaf_size -= sizeof(u32);
-
- /* Update the Extended ROM leaf length */
- cache->ext_rom->value.leaf.len =
- bytes_to_quads(leaf_size);
- } else {
- /* Zero out the unused ROM region */
- memset(cache->data + bytes_to_quads(cache->len), 0x00,
- cache->size - cache->len);
- }
-
- /* Copy the data into the cache buffer */
- csr1212_fill_cache(cache);
-
- if (cache != csr->cache_head) {
- /* Set the length and CRC of the extended ROM. */
- struct csr1212_keyval_img *kvi =
- (struct csr1212_keyval_img*)cache->data;
- u16 len = bytes_to_quads(cache->len) - 1;
-
- kvi->length = cpu_to_be16(len);
- kvi->crc = csr1212_crc16(kvi->data, len);
- }
- }
-
- return CSR1212_SUCCESS;
-}
-
-int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
-{
- struct csr1212_csr_rom_cache *cache;
-
- for (cache = csr->cache_head; cache; cache = cache->next)
- if (offset >= cache->offset &&
- (offset + len) <= (cache->offset + cache->size)) {
- memcpy(buffer, &cache->data[
- bytes_to_quads(offset - cache->offset)],
- len);
- return CSR1212_SUCCESS;
- }
-
- return -ENOENT;
-}
-
-/*
- * Apparently there are many different wrong implementations of the CRC
- * algorithm. We don't fail, we just warn... approximately once per GUID.
- */
-static void
-csr1212_check_crc(const u32 *buffer, size_t length, u16 crc, __be32 *guid)
-{
- static u64 last_bad_eui64;
- u64 eui64 = ((u64)be32_to_cpu(guid[0]) << 32) | be32_to_cpu(guid[1]);
-
- if (csr1212_crc16(buffer, length) == crc ||
- csr1212_msft_crc16(buffer, length) == crc ||
- eui64 == last_bad_eui64)
- return;
-
- printk(KERN_DEBUG "ieee1394: config ROM CRC error\n");
- last_bad_eui64 = eui64;
-}
-
-/* Parse a chunk of data as a Config ROM */
-
-static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
-{
- struct csr1212_bus_info_block_img *bi;
- struct csr1212_cache_region *cr;
- int i;
- int ret;
-
- for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
- ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
- &csr->cache_head->data[bytes_to_quads(i)],
- csr->private);
- if (ret != CSR1212_SUCCESS)
- return ret;
-
- /* check ROM header's info_length */
- if (i == 0 &&
- be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
- bytes_to_quads(csr->bus_info_len) - 1)
- return -EINVAL;
- }
-
- bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
- csr->crc_len = quads_to_bytes(bi->crc_length);
-
- /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that
- * is not always the case, so read the rest of the crc area 1 quadlet at
- * a time. */
- for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
- ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
- &csr->cache_head->data[bytes_to_quads(i)],
- csr->private);
- if (ret != CSR1212_SUCCESS)
- return ret;
- }
-
- csr1212_check_crc(bi->data, bi->crc_length, bi->crc,
- &csr->bus_info_data[3]);
-
- cr = CSR1212_MALLOC(sizeof(*cr));
- if (!cr)
- return -ENOMEM;
-
- cr->next = NULL;
- cr->prev = NULL;
- cr->offset_start = 0;
- cr->offset_end = csr->crc_len + 4;
-
- csr->cache_head->filled_head = cr;
- csr->cache_head->filled_tail = cr;
-
- return CSR1212_SUCCESS;
-}
-
-#define CSR1212_KV_KEY(q) (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
-#define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
-#define CSR1212_KV_KEY_ID(q) (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
-#define CSR1212_KV_VAL_MASK 0xffffff
-#define CSR1212_KV_VAL(q) (be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
-
-static int
-csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
-{
- int ret = CSR1212_SUCCESS;
- struct csr1212_keyval *k = NULL;
- u32 offset;
- bool keep_keyval = true;
-
- switch (CSR1212_KV_KEY_TYPE(ki)) {
- case CSR1212_KV_TYPE_IMMEDIATE:
- k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
- CSR1212_KV_VAL(ki));
- if (!k) {
- ret = -ENOMEM;
- goto out;
- }
- /* Don't keep local reference when parsing. */
- keep_keyval = false;
- break;
-
- case CSR1212_KV_TYPE_CSR_OFFSET:
- k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
- CSR1212_KV_VAL(ki));
- if (!k) {
- ret = -ENOMEM;
- goto out;
- }
- /* Don't keep local reference when parsing. */
- keep_keyval = false;
- break;
-
- default:
- /* Compute the offset from 0xffff f000 0000. */
- offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;
- if (offset == kv_pos) {
- /* Uh-oh. Can't have a relative offset of 0 for Leaves
- * or Directories. The Config ROM image is most likely
- * messed up, so we'll just abort here. */
- ret = -EIO;
- goto out;
- }
-
- k = csr1212_find_keyval_offset(dir, offset);
-
- if (k)
- break; /* Found it. */
-
- if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY)
- k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
- else
- k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
-
- if (!k) {
- ret = -ENOMEM;
- goto out;
- }
- /* Don't keep local reference when parsing. */
- keep_keyval = false;
- /* Contents not read yet so it's not valid. */
- k->valid = 0;
- k->offset = offset;
-
- k->prev = dir;
- k->next = dir->next;
- dir->next->prev = k;
- dir->next = k;
- }
- ret = __csr1212_attach_keyval_to_directory(dir, k, keep_keyval);
-out:
- if (ret != CSR1212_SUCCESS && k != NULL)
- free_keyval(k);
- return ret;
-}
-
-int csr1212_parse_keyval(struct csr1212_keyval *kv,
- struct csr1212_csr_rom_cache *cache)
-{
- struct csr1212_keyval_img *kvi;
- int i;
- int ret = CSR1212_SUCCESS;
- int kvi_len;
-
- kvi = (struct csr1212_keyval_img*)
- &cache->data[bytes_to_quads(kv->offset - cache->offset)];
- kvi_len = be16_to_cpu(kvi->length);
-
- /* GUID is wrong in here in case of extended ROM. We don't care. */
- csr1212_check_crc(kvi->data, kvi_len, kvi->crc, &cache->data[3]);
-
- switch (kv->key.type) {
- case CSR1212_KV_TYPE_DIRECTORY:
- for (i = 0; i < kvi_len; i++) {
- u32 ki = kvi->data[i];
-
- /* Some devices put null entries in their unit
- * directories. If we come across such an entry,
- * then skip it. */
- if (ki == 0x0)
- continue;
- ret = csr1212_parse_dir_entry(kv, ki,
- kv->offset + quads_to_bytes(i + 1));
- }
- kv->value.directory.len = kvi_len;
- break;
-
- case CSR1212_KV_TYPE_LEAF:
- if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
- size_t size = quads_to_bytes(kvi_len);
-
- kv->value.leaf.data = CSR1212_MALLOC(size);
- if (!kv->value.leaf.data) {
- ret = -ENOMEM;
- goto out;
- }
-
- kv->value.leaf.len = kvi_len;
- memcpy(kv->value.leaf.data, kvi->data, size);
- }
- break;
- }
-
- kv->valid = 1;
-out:
- return ret;
-}
-
-static int
-csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
-{
- struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
- struct csr1212_keyval_img *kvi = NULL;
- struct csr1212_csr_rom_cache *cache;
- int cache_index;
- u64 addr;
- u32 *cache_ptr;
- u16 kv_len = 0;
-
- BUG_ON(!csr || !kv || csr->max_rom < 1);
-
- /* First find which cache the data should be in (or go in if not read
- * yet). */
- for (cache = csr->cache_head; cache; cache = cache->next)
- if (kv->offset >= cache->offset &&
- kv->offset < (cache->offset + cache->size))
- break;
-
- if (!cache) {
- u32 q, cache_size;
-
- /* Only create a new cache for Extended ROM leaves. */
- if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
- return -EINVAL;
-
- if (csr->ops->bus_read(csr,
- CSR1212_REGISTER_SPACE_BASE + kv->offset,
- &q, csr->private))
- return -EIO;
-
- kv->value.leaf.len = be32_to_cpu(q) >> 16;
-
- cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
- (csr->max_rom - 1)) & ~(csr->max_rom - 1);
-
- cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
- if (!cache)
- return -ENOMEM;
-
- kv->value.leaf.data = &cache->data[1];
- csr->cache_tail->next = cache;
- cache->prev = csr->cache_tail;
- cache->next = NULL;
- csr->cache_tail = cache;
- cache->filled_head =
- CSR1212_MALLOC(sizeof(*cache->filled_head));
- if (!cache->filled_head)
- return -ENOMEM;
-
- cache->filled_head->offset_start = 0;
- cache->filled_head->offset_end = sizeof(u32);
- cache->filled_tail = cache->filled_head;
- cache->filled_head->next = NULL;
- cache->filled_head->prev = NULL;
- cache->data[0] = q;
-
- /* Don't read the entire extended ROM now. Pieces of it will
- * be read when entries inside it are read. */
- return csr1212_parse_keyval(kv, cache);
- }
-
- cache_index = kv->offset - cache->offset;
-
- /* Now seach read portions of the cache to see if it is there. */
- for (cr = cache->filled_head; cr; cr = cr->next) {
- if (cache_index < cr->offset_start) {
- newcr = CSR1212_MALLOC(sizeof(*newcr));
- if (!newcr)
- return -ENOMEM;
-
- newcr->offset_start = cache_index & ~(csr->max_rom - 1);
- newcr->offset_end = newcr->offset_start;
- newcr->next = cr;
- newcr->prev = cr->prev;
- cr->prev = newcr;
- cr = newcr;
- break;
- } else if ((cache_index >= cr->offset_start) &&
- (cache_index < cr->offset_end)) {
- kvi = (struct csr1212_keyval_img*)
- (&cache->data[bytes_to_quads(cache_index)]);
- kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
- break;
- } else if (cache_index == cr->offset_end) {
- break;
- }
- }
-
- if (!cr) {
- cr = cache->filled_tail;
- newcr = CSR1212_MALLOC(sizeof(*newcr));
- if (!newcr)
- return -ENOMEM;
-
- newcr->offset_start = cache_index & ~(csr->max_rom - 1);
- newcr->offset_end = newcr->offset_start;
- newcr->prev = cr;
- newcr->next = cr->next;
- cr->next = newcr;
- cr = newcr;
- cache->filled_tail = newcr;
- }
-
- while(!kvi || cr->offset_end < cache_index + kv_len) {
- cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &
- ~(csr->max_rom - 1))];
-
- addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
- cr->offset_end) & ~(csr->max_rom - 1);
-
- if (csr->ops->bus_read(csr, addr, cache_ptr, csr->private))
- return -EIO;
-
- cr->offset_end += csr->max_rom - (cr->offset_end &
- (csr->max_rom - 1));
-
- if (!kvi && (cr->offset_end > cache_index)) {
- kvi = (struct csr1212_keyval_img*)
- (&cache->data[bytes_to_quads(cache_index)]);
- kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
- }
-
- if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
- /* The Leaf or Directory claims its length extends
- * beyond the ConfigROM image region and thus beyond the
- * end of our cache region. Therefore, we abort now
- * rather than seg faulting later. */
- return -EIO;
- }
-
- ncr = cr->next;
-
- if (ncr && (cr->offset_end >= ncr->offset_start)) {
- /* consolidate region entries */
- ncr->offset_start = cr->offset_start;
-
- if (cr->prev)
- cr->prev->next = cr->next;
- ncr->prev = cr->prev;
- if (cache->filled_head == cr)
- cache->filled_head = ncr;
- CSR1212_FREE(cr);
- cr = ncr;
- }
- }
-
- return csr1212_parse_keyval(kv, cache);
-}
-
-struct csr1212_keyval *
-csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
-{
- if (!kv)
- return NULL;
- if (!kv->valid)
- if (csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
- return NULL;
- return kv;
-}
-
-int csr1212_parse_csr(struct csr1212_csr *csr)
-{
- struct csr1212_dentry *dentry;
- int ret;
-
- BUG_ON(!csr || !csr->ops || !csr->ops->bus_read);
-
- ret = csr1212_parse_bus_info_block(csr);
- if (ret != CSR1212_SUCCESS)
- return ret;
-
- /*
- * There has been a buggy firmware with bus_info_block.max_rom > 0
- * spotted which actually only supported quadlet read requests to the
- * config ROM. Therefore read everything quadlet by quadlet regardless
- * of what the bus info block says.
- */
- csr->max_rom = 4;
-
- csr->cache_head->layout_head = csr->root_kv;
- csr->cache_head->layout_tail = csr->root_kv;
-
- csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +
- csr->bus_info_len;
-
- csr->root_kv->valid = 0;
- csr->root_kv->next = csr->root_kv;
- csr->root_kv->prev = csr->root_kv;
- ret = csr1212_read_keyval(csr, csr->root_kv);
- if (ret != CSR1212_SUCCESS)
- return ret;
-
- /* Scan through the Root directory finding all extended ROM regions
- * and make cache regions for them */
- for (dentry = csr->root_kv->value.directory.dentries_head;
- dentry; dentry = dentry->next) {
- if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
- !dentry->kv->valid) {
- ret = csr1212_read_keyval(csr, dentry->kv);
- if (ret != CSR1212_SUCCESS)
- return ret;
- }
- }
-
- return CSR1212_SUCCESS;
-}
diff --git a/drivers/ieee1394/csr1212.h b/drivers/ieee1394/csr1212.h
deleted file mode 100644
index a892d922dbc9..000000000000
--- a/drivers/ieee1394/csr1212.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * csr1212.h -- IEEE 1212 Control and Status Register support for Linux
- *
- * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
- * Steve Kinneberg <kinnebergsteve@acmsystems.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 __CSR1212_H__
-#define __CSR1212_H__
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/atomic.h>
-
-#define CSR1212_MALLOC(size) kmalloc((size), GFP_KERNEL)
-#define CSR1212_FREE(ptr) kfree(ptr)
-
-#define CSR1212_SUCCESS (0)
-
-
-/* CSR 1212 key types */
-#define CSR1212_KV_TYPE_IMMEDIATE 0
-#define CSR1212_KV_TYPE_CSR_OFFSET 1
-#define CSR1212_KV_TYPE_LEAF 2
-#define CSR1212_KV_TYPE_DIRECTORY 3
-
-
-/* CSR 1212 key ids */
-#define CSR1212_KV_ID_DESCRIPTOR 0x01
-#define CSR1212_KV_ID_BUS_DEPENDENT_INFO 0x02
-#define CSR1212_KV_ID_VENDOR 0x03
-#define CSR1212_KV_ID_HARDWARE_VERSION 0x04
-#define CSR1212_KV_ID_MODULE 0x07
-#define CSR1212_KV_ID_NODE_CAPABILITIES 0x0C
-#define CSR1212_KV_ID_EUI_64 0x0D
-#define CSR1212_KV_ID_UNIT 0x11
-#define CSR1212_KV_ID_SPECIFIER_ID 0x12
-#define CSR1212_KV_ID_VERSION 0x13
-#define CSR1212_KV_ID_DEPENDENT_INFO 0x14
-#define CSR1212_KV_ID_UNIT_LOCATION 0x15
-#define CSR1212_KV_ID_MODEL 0x17
-#define CSR1212_KV_ID_INSTANCE 0x18
-#define CSR1212_KV_ID_KEYWORD 0x19
-#define CSR1212_KV_ID_FEATURE 0x1A
-#define CSR1212_KV_ID_EXTENDED_ROM 0x1B
-#define CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID 0x1C
-#define CSR1212_KV_ID_EXTENDED_KEY 0x1D
-#define CSR1212_KV_ID_EXTENDED_DATA 0x1E
-#define CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR 0x1F
-#define CSR1212_KV_ID_DIRECTORY_ID 0x20
-#define CSR1212_KV_ID_REVISION 0x21
-
-
-/* IEEE 1212 Address space map */
-#define CSR1212_ALL_SPACE_BASE (0x000000000000ULL)
-#define CSR1212_ALL_SPACE_SIZE (1ULL << 48)
-#define CSR1212_ALL_SPACE_END (CSR1212_ALL_SPACE_BASE + CSR1212_ALL_SPACE_SIZE)
-
-#define CSR1212_MEMORY_SPACE_BASE (0x000000000000ULL)
-#define CSR1212_MEMORY_SPACE_SIZE ((256ULL * (1ULL << 40)) - (512ULL * (1ULL << 20)))
-#define CSR1212_MEMORY_SPACE_END (CSR1212_MEMORY_SPACE_BASE + CSR1212_MEMORY_SPACE_SIZE)
-
-#define CSR1212_PRIVATE_SPACE_BASE (0xffffe0000000ULL)
-#define CSR1212_PRIVATE_SPACE_SIZE (256ULL * (1ULL << 20))
-#define CSR1212_PRIVATE_SPACE_END (CSR1212_PRIVATE_SPACE_BASE + CSR1212_PRIVATE_SPACE_SIZE)
-
-#define CSR1212_REGISTER_SPACE_BASE (0xfffff0000000ULL)
-#define CSR1212_REGISTER_SPACE_SIZE (256ULL * (1ULL << 20))
-#define CSR1212_REGISTER_SPACE_END (CSR1212_REGISTER_SPACE_BASE + CSR1212_REGISTER_SPACE_SIZE)
-
-#define CSR1212_CSR_ARCH_REG_SPACE_BASE (0xfffff0000000ULL)
-#define CSR1212_CSR_ARCH_REG_SPACE_SIZE (512)
-#define CSR1212_CSR_ARCH_REG_SPACE_END (CSR1212_CSR_ARCH_REG_SPACE_BASE + CSR1212_CSR_ARCH_REG_SPACE_SIZE)
-#define CSR1212_CSR_ARCH_REG_SPACE_OFFSET (CSR1212_CSR_ARCH_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define CSR1212_CSR_BUS_DEP_REG_SPACE_BASE (0xfffff0000200ULL)
-#define CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE (512)
-#define CSR1212_CSR_BUS_DEP_REG_SPACE_END (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE + CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE)
-#define CSR1212_CSR_BUS_DEP_REG_SPACE_OFFSET (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define CSR1212_CONFIG_ROM_SPACE_BASE (0xfffff0000400ULL)
-#define CSR1212_CONFIG_ROM_SPACE_SIZE (1024)
-#define CSR1212_CONFIG_ROM_SPACE_END (CSR1212_CONFIG_ROM_SPACE_BASE + CSR1212_CONFIG_ROM_SPACE_SIZE)
-#define CSR1212_CONFIG_ROM_SPACE_OFFSET (CSR1212_CONFIG_ROM_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define CSR1212_UNITS_SPACE_BASE (0xfffff0000800ULL)
-#define CSR1212_UNITS_SPACE_SIZE ((256ULL * (1ULL << 20)) - 2048)
-#define CSR1212_UNITS_SPACE_END (CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE)
-#define CSR1212_UNITS_SPACE_OFFSET (CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define CSR1212_INVALID_ADDR_SPACE -1
-
-
-/* Config ROM image structures */
-struct csr1212_bus_info_block_img {
- u8 length;
- u8 crc_length;
- u16 crc;
-
- /* Must be last */
- u32 data[0]; /* older gcc can't handle [] which is standard */
-};
-
-struct csr1212_leaf {
- int len;
- u32 *data;
-};
-
-struct csr1212_dentry {
- struct csr1212_dentry *next, *prev;
- struct csr1212_keyval *kv;
-};
-
-struct csr1212_directory {
- int len;
- struct csr1212_dentry *dentries_head, *dentries_tail;
-};
-
-struct csr1212_keyval {
- struct {
- u8 type;
- u8 id;
- } key;
- union {
- u32 immediate;
- u32 csr_offset;
- struct csr1212_leaf leaf;
- struct csr1212_directory directory;
- } value;
- struct csr1212_keyval *associate;
- atomic_t refcnt;
-
- /* used in generating and/or parsing CSR image */
- struct csr1212_keyval *next, *prev; /* flat list of CSR elements */
- u32 offset; /* position in CSR from 0xffff f000 0000 */
- u8 valid; /* flag indicating keyval has valid data*/
-};
-
-
-struct csr1212_cache_region {
- struct csr1212_cache_region *next, *prev;
- u32 offset_start; /* inclusive */
- u32 offset_end; /* exclusive */
-};
-
-struct csr1212_csr_rom_cache {
- struct csr1212_csr_rom_cache *next, *prev;
- struct csr1212_cache_region *filled_head, *filled_tail;
- struct csr1212_keyval *layout_head, *layout_tail;
- size_t size;
- u32 offset;
- struct csr1212_keyval *ext_rom;
- size_t len;
-
- /* Must be last */
- u32 data[0]; /* older gcc can't handle [] which is standard */
-};
-
-struct csr1212_csr {
- size_t bus_info_len; /* bus info block length in bytes */
- size_t crc_len; /* crc length in bytes */
- __be32 *bus_info_data; /* bus info data incl bus name and EUI */
-
- void *private; /* private, bus specific data */
- struct csr1212_bus_ops *ops;
-
- struct csr1212_keyval *root_kv;
-
- int max_rom; /* max bytes readable in Config ROM region */
-
- /* Items below used for image parsing and generation */
- struct csr1212_csr_rom_cache *cache_head, *cache_tail;
-};
-
-struct csr1212_bus_ops {
- /* This function is used by csr1212 to read additional information
- * from remote nodes when parsing a Config ROM (i.e., read Config ROM
- * entries located in the Units Space. Must return 0 on success
- * anything else indicates an error. */
- int (*bus_read) (struct csr1212_csr *csr, u64 addr,
- void *buffer, void *private);
-
- /* This function is used by csr1212 to allocate a region in units space
- * in the event that Config ROM entries don't all fit in the predefined
- * 1K region. The void *private parameter is private member of struct
- * csr1212_csr. */
- u64 (*allocate_addr_range) (u64 size, u32 alignment, void *private);
-
- /* This function is used by csr1212 to release a region in units space
- * that is no longer needed. */
- void (*release_addr) (u64 addr, void *private);
-};
-
-
-/* Descriptor Leaf manipulation macros */
-#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
-#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
-#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
-
-#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
- (be32_to_cpu((kv)->value.leaf.data[0]) >> \
- CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
-#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
- (be32_to_cpu((kv)->value.leaf.data[0]) & \
- CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)
-
-
-/* Text Descriptor Leaf manipulation macros */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK 0xf /* after shift */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff /* after shift */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
-
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
- (be32_to_cpu((kv)->value.leaf.data[1]) >> \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
- ((be32_to_cpu((kv)->value.leaf.data[1]) >> \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
- (be32_to_cpu((kv)->value.leaf.data[1]) & \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
- (&((kv)->value.leaf.data[2]))
-
-
-/* The following 2 function are for creating new Configuration ROM trees. The
- * first function is used for both creating local trees and parsing remote
- * trees. The second function adds pertinent information to local Configuration
- * ROM trees - namely data for the bus information block. */
-extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
- size_t bus_info_size,
- void *private);
-extern void csr1212_init_local_csr(struct csr1212_csr *csr,
- const u32 *bus_info_data, int max_rom);
-
-
-/* Destroy a Configuration ROM tree and release all memory taken by the tree. */
-extern void csr1212_destroy_csr(struct csr1212_csr *csr);
-
-
-/* The following set of functions are fore creating new keyvals for placement in
- * a Configuration ROM tree. Code that creates new keyvals with these functions
- * must release those keyvals with csr1212_release_keyval() when they are no
- * longer needed. */
-extern struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value);
-extern struct csr1212_keyval *csr1212_new_directory(u8 key);
-extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s);
-
-
-/* The following function manages association between keyvals. Typically,
- * Descriptor Leaves and Directories will be associated with another keyval and
- * it is desirable for the Descriptor keyval to be place immediately after the
- * keyval that it is associated with.
- * Take care with subsequent ROM modifications: There is no function to remove
- * previously specified associations.
- */
-extern void csr1212_associate_keyval(struct csr1212_keyval *kv,
- struct csr1212_keyval *associate);
-
-
-/* The following functions manage the association of a keyval and directories.
- * A keyval may be attached to more than one directory. */
-extern int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv);
-extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv);
-
-
-/* Creates a complete Configuration ROM image in the list of caches available
- * via csr->cache_head. */
-extern int csr1212_generate_csr_image(struct csr1212_csr *csr);
-
-
-/* This is a convience function for reading a block of data out of one of the
- * caches in the csr->cache_head list. */
-extern int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer,
- u32 len);
-
-
-/* The following functions are in place for parsing Configuration ROM images.
- * csr1212_parse_keyval() is used should there be a need to directly parse a
- * Configuration ROM directly. */
-extern int csr1212_parse_keyval(struct csr1212_keyval *kv,
- struct csr1212_csr_rom_cache *cache);
-extern int csr1212_parse_csr(struct csr1212_csr *csr);
-
-
-/* This function allocates a new cache which may be used for either parsing or
- * generating sub-sets of Configuration ROM images. */
-static inline struct csr1212_csr_rom_cache *
-csr1212_rom_cache_malloc(u32 offset, size_t size)
-{
- struct csr1212_csr_rom_cache *cache;
-
- cache = CSR1212_MALLOC(sizeof(*cache) + size);
- if (!cache)
- return NULL;
-
- cache->next = NULL;
- cache->prev = NULL;
- cache->filled_head = NULL;
- cache->filled_tail = NULL;
- cache->layout_head = NULL;
- cache->layout_tail = NULL;
- cache->offset = offset;
- cache->size = size;
- cache->ext_rom = NULL;
-
- return cache;
-}
-
-
-/* This function ensures that a keyval contains data when referencing a keyval
- * created by parsing a Configuration ROM. */
-extern struct csr1212_keyval *
-csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
-
-
-/* This function increments the reference count for a keyval should there be a
- * need for code to retain a keyval that has been parsed. */
-static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
-{
- atomic_inc(&kv->refcnt);
- smp_mb__after_atomic_inc();
-}
-
-
-/* This function decrements a keyval's reference count and will destroy the
- * keyval when there are no more users of the keyval. This should be called by
- * any code that calls csr1212_keep_keyval() or any of the keyval creation
- * routines csr1212_new_*(). */
-extern void csr1212_release_keyval(struct csr1212_keyval *kv);
-
-
-/*
- * This macro allows for looping over the keyval entries in a directory and it
- * ensures that keyvals from remote ConfigROMs are parsed properly.
- *
- * struct csr1212_csr *_csr points to the CSR associated with dir.
- * struct csr1212_keyval *_kv points to the current keyval (loop index).
- * struct csr1212_keyval *_dir points to the directory to be looped.
- * struct csr1212_dentry *_pos is used internally for indexing.
- *
- * kv will be NULL upon exit of the loop.
- */
-#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \
- for (csr1212_get_keyval((_csr), (_dir)), \
- _pos = (_dir)->value.directory.dentries_head, \
- _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;\
- (_kv) && (_pos); \
- (_kv->associate == NULL) ? \
- ((_pos = _pos->next), (_kv = (_pos) ? \
- csr1212_get_keyval((_csr), _pos->kv) : \
- NULL)) : \
- (_kv = csr1212_get_keyval((_csr), _kv->associate)))
-
-#endif /* __CSR1212_H__ */
diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
deleted file mode 100644
index d178699b194a..000000000000
--- a/drivers/ieee1394/dma.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * DMA region bookkeeping routines
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/scatterlist.h>
-
-#include "dma.h"
-
-/* dma_prog_region */
-
-void dma_prog_region_init(struct dma_prog_region *prog)
-{
- prog->kvirt = NULL;
- prog->dev = NULL;
- prog->n_pages = 0;
- prog->bus_addr = 0;
-}
-
-int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
- struct pci_dev *dev)
-{
- /* round up to page size */
- n_bytes = PAGE_ALIGN(n_bytes);
-
- prog->n_pages = n_bytes >> PAGE_SHIFT;
-
- prog->kvirt = pci_alloc_consistent(dev, n_bytes, &prog->bus_addr);
- if (!prog->kvirt) {
- printk(KERN_ERR
- "dma_prog_region_alloc: pci_alloc_consistent() failed\n");
- dma_prog_region_free(prog);
- return -ENOMEM;
- }
-
- prog->dev = dev;
-
- return 0;
-}
-
-void dma_prog_region_free(struct dma_prog_region *prog)
-{
- if (prog->kvirt) {
- pci_free_consistent(prog->dev, prog->n_pages << PAGE_SHIFT,
- prog->kvirt, prog->bus_addr);
- }
-
- prog->kvirt = NULL;
- prog->dev = NULL;
- prog->n_pages = 0;
- prog->bus_addr = 0;
-}
-
-/* dma_region */
-
-/**
- * dma_region_init - clear out all fields but do not allocate anything
- */
-void dma_region_init(struct dma_region *dma)
-{
- dma->kvirt = NULL;
- dma->dev = NULL;
- dma->n_pages = 0;
- dma->n_dma_pages = 0;
- dma->sglist = NULL;
-}
-
-/**
- * dma_region_alloc - allocate the buffer and map it to the IOMMU
- */
-int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
- struct pci_dev *dev, int direction)
-{
- unsigned int i;
-
- /* round up to page size */
- n_bytes = PAGE_ALIGN(n_bytes);
-
- dma->n_pages = n_bytes >> PAGE_SHIFT;
-
- dma->kvirt = vmalloc_32(n_bytes);
- if (!dma->kvirt) {
- printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n");
- goto err;
- }
-
- /* Clear the ram out, no junk to the user */
- memset(dma->kvirt, 0, n_bytes);
-
- /* allocate scatter/gather list */
- dma->sglist = vmalloc(dma->n_pages * sizeof(*dma->sglist));
- if (!dma->sglist) {
- printk(KERN_ERR "dma_region_alloc: vmalloc(sglist) failed\n");
- goto err;
- }
-
- sg_init_table(dma->sglist, dma->n_pages);
-
- /* fill scatter/gather list with pages */
- for (i = 0; i < dma->n_pages; i++) {
- unsigned long va =
- (unsigned long)dma->kvirt + (i << PAGE_SHIFT);
-
- sg_set_page(&dma->sglist[i], vmalloc_to_page((void *)va),
- PAGE_SIZE, 0);
- }
-
- /* map sglist to the IOMMU */
- dma->n_dma_pages =
- pci_map_sg(dev, dma->sglist, dma->n_pages, direction);
-
- if (dma->n_dma_pages == 0) {
- printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n");
- goto err;
- }
-
- dma->dev = dev;
- dma->direction = direction;
-
- return 0;
-
- err:
- dma_region_free(dma);
- return -ENOMEM;
-}
-
-/**
- * dma_region_free - unmap and free the buffer
- */
-void dma_region_free(struct dma_region *dma)
-{
- if (dma->n_dma_pages) {
- pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages,
- dma->direction);
- dma->n_dma_pages = 0;
- dma->dev = NULL;
- }
-
- vfree(dma->sglist);
- dma->sglist = NULL;
-
- vfree(dma->kvirt);
- dma->kvirt = NULL;
- dma->n_pages = 0;
-}
-
-/* find the scatterlist index and remaining offset corresponding to a
- given offset from the beginning of the buffer */
-static inline int dma_region_find(struct dma_region *dma, unsigned long offset,
- unsigned int start, unsigned long *rem)
-{
- int i;
- unsigned long off = offset;
-
- for (i = start; i < dma->n_dma_pages; i++) {
- if (off < sg_dma_len(&dma->sglist[i])) {
- *rem = off;
- break;
- }
-
- off -= sg_dma_len(&dma->sglist[i]);
- }
-
- BUG_ON(i >= dma->n_dma_pages);
-
- return i;
-}
-
-/**
- * dma_region_offset_to_bus - get bus address of an offset within a DMA region
- *
- * Returns the DMA bus address of the byte with the given @offset relative to
- * the beginning of the @dma.
- */
-dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
- unsigned long offset)
-{
- unsigned long rem = 0;
-
- struct scatterlist *sg =
- &dma->sglist[dma_region_find(dma, offset, 0, &rem)];
- return sg_dma_address(sg) + rem;
-}
-
-/**
- * dma_region_sync_for_cpu - sync the CPU's view of the buffer
- */
-void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
- unsigned long len)
-{
- int first, last;
- unsigned long rem = 0;
-
- if (!len)
- len = 1;
-
- first = dma_region_find(dma, offset, 0, &rem);
- last = dma_region_find(dma, rem + len - 1, first, &rem);
-
- pci_dma_sync_sg_for_cpu(dma->dev, &dma->sglist[first], last - first + 1,
- dma->direction);
-}
-
-/**
- * dma_region_sync_for_device - sync the IO bus' view of the buffer
- */
-void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
- unsigned long len)
-{
- int first, last;
- unsigned long rem = 0;
-
- if (!len)
- len = 1;
-
- first = dma_region_find(dma, offset, 0, &rem);
- last = dma_region_find(dma, rem + len - 1, first, &rem);
-
- pci_dma_sync_sg_for_device(dma->dev, &dma->sglist[first],
- last - first + 1, dma->direction);
-}
-
-#ifdef CONFIG_MMU
-
-static int dma_region_pagefault(struct vm_area_struct *vma,
- struct vm_fault *vmf)
-{
- struct dma_region *dma = (struct dma_region *)vma->vm_private_data;
-
- if (!dma->kvirt)
- return VM_FAULT_SIGBUS;
-
- if (vmf->pgoff >= dma->n_pages)
- return VM_FAULT_SIGBUS;
-
- vmf->page = vmalloc_to_page(dma->kvirt + (vmf->pgoff << PAGE_SHIFT));
- get_page(vmf->page);
- return 0;
-}
-
-static const struct vm_operations_struct dma_region_vm_ops = {
- .fault = dma_region_pagefault,
-};
-
-/**
- * dma_region_mmap - map the buffer into a user space process
- */
-int dma_region_mmap(struct dma_region *dma, struct file *file,
- struct vm_area_struct *vma)
-{
- unsigned long size;
-
- if (!dma->kvirt)
- return -EINVAL;
-
- /* must be page-aligned (XXX: comment is wrong, we could allow pgoff) */
- if (vma->vm_pgoff != 0)
- return -EINVAL;
-
- /* check the length */
- size = vma->vm_end - vma->vm_start;
- if (size > (dma->n_pages << PAGE_SHIFT))
- return -EINVAL;
-
- vma->vm_ops = &dma_region_vm_ops;
- vma->vm_private_data = dma;
- vma->vm_file = file;
- vma->vm_flags |= VM_RESERVED | VM_ALWAYSDUMP;
-
- return 0;
-}
-
-#else /* CONFIG_MMU */
-
-int dma_region_mmap(struct dma_region *dma, struct file *file,
- struct vm_area_struct *vma)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_MMU */
diff --git a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h
deleted file mode 100644
index 467373cab8e5..000000000000
--- a/drivers/ieee1394/dma.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * DMA region bookkeeping routines
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#ifndef IEEE1394_DMA_H
-#define IEEE1394_DMA_H
-
-#include <asm/types.h>
-
-struct file;
-struct pci_dev;
-struct scatterlist;
-struct vm_area_struct;
-
-/**
- * struct dma_prog_region - small contiguous DMA buffer
- * @kvirt: kernel virtual address
- * @dev: PCI device
- * @n_pages: number of kernel pages
- * @bus_addr: base bus address
- *
- * a small, physically contiguous DMA buffer with random-access, synchronous
- * usage characteristics
- */
-struct dma_prog_region {
- unsigned char *kvirt;
- struct pci_dev *dev;
- unsigned int n_pages;
- dma_addr_t bus_addr;
-};
-
-/* clear out all fields but do not allocate any memory */
-void dma_prog_region_init(struct dma_prog_region *prog);
-int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
- struct pci_dev *dev);
-void dma_prog_region_free(struct dma_prog_region *prog);
-
-static inline dma_addr_t dma_prog_region_offset_to_bus(
- struct dma_prog_region *prog, unsigned long offset)
-{
- return prog->bus_addr + offset;
-}
-
-/**
- * struct dma_region - large non-contiguous DMA buffer
- * @virt: kernel virtual address
- * @dev: PCI device
- * @n_pages: number of kernel pages
- * @n_dma_pages: number of IOMMU pages
- * @sglist: IOMMU mapping
- * @direction: PCI_DMA_TODEVICE, etc.
- *
- * a large, non-physically-contiguous DMA buffer with streaming, asynchronous
- * usage characteristics
- */
-struct dma_region {
- unsigned char *kvirt;
- struct pci_dev *dev;
- unsigned int n_pages;
- unsigned int n_dma_pages;
- struct scatterlist *sglist;
- int direction;
-};
-
-void dma_region_init(struct dma_region *dma);
-int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
- struct pci_dev *dev, int direction);
-void dma_region_free(struct dma_region *dma);
-void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
- unsigned long len);
-void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
- unsigned long len);
-int dma_region_mmap(struct dma_region *dma, struct file *file,
- struct vm_area_struct *vma);
-dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
- unsigned long offset);
-
-/**
- * dma_region_i - macro to index into a DMA region (or dma_prog_region)
- */
-#define dma_region_i(_dma, _type, _index) \
- ( ((_type*) ((_dma)->kvirt)) + (_index) )
-
-#endif /* IEEE1394_DMA_H */
diff --git a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h
deleted file mode 100644
index 18b92cbf4a9f..000000000000
--- a/drivers/ieee1394/dv1394-private.h
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips
- * Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- * receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- * video1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _DV_1394_PRIVATE_H
-#define _DV_1394_PRIVATE_H
-
-#include "ieee1394.h"
-#include "ohci1394.h"
-#include "dma.h"
-
-/* data structures private to the dv1394 driver */
-/* none of this is exposed to user-space */
-
-
-/*
- the 8-byte CIP (Common Isochronous Packet) header that precedes
- each packet of DV data.
-
- See the IEC 61883 standard.
-*/
-
-struct CIP_header { unsigned char b[8]; };
-
-static inline void fill_cip_header(struct CIP_header *cip,
- unsigned char source_node_id,
- unsigned long counter,
- enum pal_or_ntsc format,
- unsigned long timestamp)
-{
- cip->b[0] = source_node_id;
- cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */
- cip->b[2] = 0x00;
- cip->b[3] = counter;
-
- cip->b[4] = 0x80; /* const */
-
- switch(format) {
- case DV1394_PAL:
- cip->b[5] = 0x80;
- break;
- case DV1394_NTSC:
- cip->b[5] = 0x00;
- break;
- }
-
- cip->b[6] = timestamp >> 8;
- cip->b[7] = timestamp & 0xFF;
-}
-
-
-
-/*
- DMA commands used to program the OHCI's DMA engine
-
- See the Texas Instruments OHCI 1394 chipset documentation.
-*/
-
-struct output_more_immediate { __le32 q[8]; };
-struct output_more { __le32 q[4]; };
-struct output_last { __le32 q[4]; };
-struct input_more { __le32 q[4]; };
-struct input_last { __le32 q[4]; };
-
-/* outputs */
-
-static inline void fill_output_more_immediate(struct output_more_immediate *omi,
- unsigned char tag,
- unsigned char channel,
- unsigned char sync_tag,
- unsigned int payload_size)
-{
- omi->q[0] = cpu_to_le32(0x02000000 | 8); /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
- omi->q[1] = cpu_to_le32(0);
- omi->q[2] = cpu_to_le32(0);
- omi->q[3] = cpu_to_le32(0);
-
- /* IT packet header */
- omi->q[4] = cpu_to_le32( (0x0 << 16) /* IEEE1394_SPEED_100 */
- | (tag << 14)
- | (channel << 8)
- | (TCODE_ISO_DATA << 4)
- | (sync_tag) );
-
- /* reserved field; mimic behavior of my Sony DSR-40 */
- omi->q[5] = cpu_to_le32((payload_size << 16) | (0x7F << 8) | 0xA0);
-
- omi->q[6] = cpu_to_le32(0);
- omi->q[7] = cpu_to_le32(0);
-}
-
-static inline void fill_output_more(struct output_more *om,
- unsigned int data_size,
- unsigned long data_phys_addr)
-{
- om->q[0] = cpu_to_le32(data_size);
- om->q[1] = cpu_to_le32(data_phys_addr);
- om->q[2] = cpu_to_le32(0);
- om->q[3] = cpu_to_le32(0);
-}
-
-static inline void fill_output_last(struct output_last *ol,
- int want_timestamp,
- int want_interrupt,
- unsigned int data_size,
- unsigned long data_phys_addr)
-{
- u32 temp = 0;
- temp |= 1 << 28; /* OUTPUT_LAST */
-
- if (want_timestamp) /* controller will update timestamp at DMA time */
- temp |= 1 << 27;
-
- if (want_interrupt)
- temp |= 3 << 20;
-
- temp |= 3 << 18; /* must take branch */
- temp |= data_size;
-
- ol->q[0] = cpu_to_le32(temp);
- ol->q[1] = cpu_to_le32(data_phys_addr);
- ol->q[2] = cpu_to_le32(0);
- ol->q[3] = cpu_to_le32(0);
-}
-
-/* inputs */
-
-static inline void fill_input_more(struct input_more *im,
- int want_interrupt,
- unsigned int data_size,
- unsigned long data_phys_addr)
-{
- u32 temp = 2 << 28; /* INPUT_MORE */
- temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
- if (want_interrupt)
- temp |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
- temp |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
- /* disable wait on sync field, not used in DV :-( */
- temp |= data_size;
-
- im->q[0] = cpu_to_le32(temp);
- im->q[1] = cpu_to_le32(data_phys_addr);
- im->q[2] = cpu_to_le32(0); /* branchAddress and Z not use in packet-per-buffer mode */
- im->q[3] = cpu_to_le32(0); /* xferStatus & resCount, resCount must be initialize to data_size */
-}
-
-static inline void fill_input_last(struct input_last *il,
- int want_interrupt,
- unsigned int data_size,
- unsigned long data_phys_addr)
-{
- u32 temp = 3 << 28; /* INPUT_LAST */
- temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
- if (want_interrupt)
- temp |= 3 << 20; /* enable interrupts */
- temp |= 0xC << 16; /* enable branch to address */
- /* disable wait on sync field, not used in DV :-( */
- temp |= data_size;
-
- il->q[0] = cpu_to_le32(temp);
- il->q[1] = cpu_to_le32(data_phys_addr);
- il->q[2] = cpu_to_le32(1); /* branchAddress (filled in later) and Z = 1 descriptor in next block */
- il->q[3] = cpu_to_le32(data_size); /* xferStatus & resCount, resCount must be initialize to data_size */
-}
-
-
-
-/*
- A "DMA descriptor block" consists of several contiguous DMA commands.
- struct DMA_descriptor_block encapsulates all of the commands necessary
- to send one packet of DV data.
-
- There are three different types of these blocks:
-
- 1) command to send an empty packet (CIP header only, no DV data):
-
- OUTPUT_MORE-Immediate <-- contains the iso header in-line
- OUTPUT_LAST <-- points to the CIP header
-
- 2) command to send a full packet when the DV data payload does NOT
- cross a page boundary:
-
- OUTPUT_MORE-Immediate <-- contains the iso header in-line
- OUTPUT_MORE <-- points to the CIP header
- OUTPUT_LAST <-- points to entire DV data payload
-
- 3) command to send a full packet when the DV payload DOES cross
- a page boundary:
-
- OUTPUT_MORE-Immediate <-- contains the iso header in-line
- OUTPUT_MORE <-- points to the CIP header
- OUTPUT_MORE <-- points to first part of DV data payload
- OUTPUT_LAST <-- points to second part of DV data payload
-
- This struct describes all three block types using unions.
-
- !!! It is vital that an even number of these descriptor blocks fit on one
- page of memory, since a block cannot cross a page boundary !!!
-
- */
-
-struct DMA_descriptor_block {
-
- union {
- struct {
- /* iso header, common to all output block types */
- struct output_more_immediate omi;
-
- union {
- /* empty packet */
- struct {
- struct output_last ol; /* CIP header */
- } empty;
-
- /* full packet */
- struct {
- struct output_more om; /* CIP header */
-
- union {
- /* payload does not cross page boundary */
- struct {
- struct output_last ol; /* data payload */
- } nocross;
-
- /* payload crosses page boundary */
- struct {
- struct output_more om; /* data payload */
- struct output_last ol; /* data payload */
- } cross;
- } u;
-
- } full;
- } u;
- } out;
-
- struct {
- struct input_last il;
- } in;
-
- } u;
-
- /* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0
- by padding out to 128 bytes */
- u32 __pad__[12];
-};
-
-
-/* struct frame contains all data associated with one frame in the
- ringbuffer these are allocated when the DMA context is initialized
- do_dv1394_init(). They are re-used after the card finishes
- transmitting the frame. */
-
-struct video_card; /* forward declaration */
-
-struct frame {
-
- /* points to the struct video_card that owns this frame */
- struct video_card *video;
-
- /* index of this frame in video_card->frames[] */
- unsigned int frame_num;
-
- /* FRAME_CLEAR - DMA program not set up, waiting for data
- FRAME_READY - DMA program written, ready to transmit
-
- Changes to these should be locked against the interrupt
- */
- enum {
- FRAME_CLEAR = 0,
- FRAME_READY
- } state;
-
- /* whether this frame has been DMA'ed already; used only from
- the IRQ handler to determine whether the frame can be reset */
- int done;
-
-
- /* kernel virtual pointer to the start of this frame's data in
- the user ringbuffer. Use only for CPU access; to get the DMA
- bus address you must go through the video->user_dma mapping */
- unsigned long data;
-
- /* Max # of packets per frame */
-#define MAX_PACKETS 500
-
-
- /* a PAGE_SIZE memory pool for allocating CIP headers
- !header_pool must be aligned to PAGE_SIZE! */
- struct CIP_header *header_pool;
- dma_addr_t header_pool_dma;
-
-
- /* a physically contiguous memory pool for allocating DMA
- descriptor blocks; usually around 64KB in size
- !descriptor_pool must be aligned to PAGE_SIZE! */
- struct DMA_descriptor_block *descriptor_pool;
- dma_addr_t descriptor_pool_dma;
- unsigned long descriptor_pool_size;
-
-
- /* # of packets allocated for this frame */
- unsigned int n_packets;
-
-
- /* below are several pointers (kernel virtual addresses, not
- DMA bus addresses) to parts of the DMA program. These are
- set each time the DMA program is written in
- frame_prepare(). They are used later on, e.g. from the
- interrupt handler, to check the status of the frame */
-
- /* points to status/timestamp field of first DMA packet */
- /* (we'll check it later to monitor timestamp accuracy) */
- __le32 *frame_begin_timestamp;
-
- /* the timestamp we assigned to the first packet in the frame */
- u32 assigned_timestamp;
-
- /* pointer to the first packet's CIP header (where the timestamp goes) */
- struct CIP_header *cip_syt1;
-
- /* pointer to the second packet's CIP header
- (only set if the first packet was empty) */
- struct CIP_header *cip_syt2;
-
- /* in order to figure out what caused an interrupt,
- store pointers to the status fields of the two packets
- that can cause interrupts. We'll check these from the
- interrupt handler.
- */
- __le32 *mid_frame_timestamp;
- __le32 *frame_end_timestamp;
-
- /* branch address field of final packet. This is effectively
- the "tail" in the chain of DMA descriptor blocks.
- We will fill it with the address of the first DMA descriptor
- block in the subsequent frame, once it is ready.
- */
- __le32 *frame_end_branch;
-
- /* the number of descriptors in the first descriptor block
- of the frame. Needed to start DMA */
- int first_n_descriptors;
-};
-
-
-struct packet {
- __le16 timestamp;
- u16 invalid;
- u16 iso_header;
- __le16 data_length;
- u32 cip_h1;
- u32 cip_h2;
- unsigned char data[480];
- unsigned char padding[16]; /* force struct size =512 for page alignment */
-};
-
-
-/* allocate/free a frame */
-static struct frame* frame_new(unsigned int frame_num, struct video_card *video);
-static void frame_delete(struct frame *f);
-
-/* reset f so that it can be used again */
-static void frame_reset(struct frame *f);
-
-/* struct video_card contains all data associated with one instance
- of the dv1394 driver
-*/
-enum modes {
- MODE_RECEIVE,
- MODE_TRANSMIT
-};
-
-struct video_card {
-
- /* ohci card to which this instance corresponds */
- struct ti_ohci *ohci;
-
- /* OHCI card id; the link between the VFS inode and a specific video_card
- (essentially the device minor number) */
- int id;
-
- /* entry in dv1394_cards */
- struct list_head list;
-
- /* OHCI card IT DMA context number, -1 if not in use */
- int ohci_it_ctx;
- struct ohci1394_iso_tasklet it_tasklet;
-
- /* register offsets for current IT DMA context, 0 if not in use */
- u32 ohci_IsoXmitContextControlSet;
- u32 ohci_IsoXmitContextControlClear;
- u32 ohci_IsoXmitCommandPtr;
-
- /* OHCI card IR DMA context number, -1 if not in use */
- struct ohci1394_iso_tasklet ir_tasklet;
- int ohci_ir_ctx;
-
- /* register offsets for current IR DMA context, 0 if not in use */
- u32 ohci_IsoRcvContextControlSet;
- u32 ohci_IsoRcvContextControlClear;
- u32 ohci_IsoRcvCommandPtr;
- u32 ohci_IsoRcvContextMatch;
-
-
- /* CONCURRENCY CONTROL */
-
- /* there are THREE levels of locking associated with video_card. */
-
- /*
- 1) the 'open' flag - this prevents more than one process from
- opening the device. (the driver currently assumes only one opener).
- This is a regular int, but use test_and_set_bit() (on bit zero)
- for atomicity.
- */
- unsigned long open;
-
- /*
- 2) the spinlock - this provides mutual exclusion between the interrupt
- handler and process-context operations. Generally you must take the
- spinlock under the following conditions:
- 1) DMA (and hence the interrupt handler) may be running
- AND
- 2) you need to operate on the video_card, especially active_frame
-
- It is OK to play with video_card without taking the spinlock if
- you are certain that DMA is not running. Even if DMA is running,
- it is OK to *read* active_frame with the lock, then drop it
- immediately. This is safe because the interrupt handler will never
- advance active_frame onto a frame that is not READY (and the spinlock
- must be held while marking a frame READY).
-
- spinlock is also used to protect ohci_it_ctx and ohci_ir_ctx,
- which can be accessed from both process and interrupt context
- */
- spinlock_t spinlock;
-
- /* flag to prevent spurious interrupts (which OHCI seems to
- generate a lot :) from accessing the struct */
- int dma_running;
-
- /*
- 3) the sleeping mutex 'mtx' - this is used from process context only,
- to serialize various operations on the video_card. Even though only one
- open() is allowed, we still need to prevent multiple threads of execution
- from entering calls like read, write, ioctl, etc.
-
- I honestly can't think of a good reason to use dv1394 from several threads
- at once, but we need to serialize anyway to prevent oopses =).
-
- NOTE: if you need both spinlock and mtx, take mtx first to avoid deadlock!
- */
- struct mutex mtx;
-
- /* people waiting for buffer space, please form a line here... */
- wait_queue_head_t waitq;
-
- /* support asynchronous I/O signals (SIGIO) */
- struct fasync_struct *fasync;
-
- /* the large, non-contiguous (rvmalloc()) ringbuffer for DV
- data, exposed to user-space via mmap() */
- unsigned long dv_buf_size;
- struct dma_region dv_buf;
-
- /* next byte in the ringbuffer that a write() call will fill */
- size_t write_off;
-
- struct frame *frames[DV1394_MAX_FRAMES];
-
- /* n_frames also serves as an indicator that this struct video_card is
- initialized and ready to run DMA buffers */
-
- int n_frames;
-
- /* this is the frame that is currently "owned" by the OHCI DMA controller
- (set to -1 iff DMA is not running)
-
- ! must lock against the interrupt handler when accessing it !
-
- RULES:
-
- Only the interrupt handler may change active_frame if DMA
- is running; if not, process may change it
-
- If the next frame is READY, the interrupt handler will advance
- active_frame when the current frame is finished.
-
- If the next frame is CLEAR, the interrupt handler will re-transmit
- the current frame, and the dropped_frames counter will be incremented.
-
- The interrupt handler will NEVER advance active_frame to a
- frame that is not READY.
- */
- int active_frame;
- int first_run;
-
- /* the same locking rules apply to these three fields also: */
-
- /* altered ONLY from process context. Must check first_clear_frame->state;
- if it's READY, that means the ringbuffer is full with READY frames;
- if it's CLEAR, that means one or more ringbuffer frames are CLEAR */
- unsigned int first_clear_frame;
-
- /* altered both by process and interrupt */
- unsigned int n_clear_frames;
-
- /* only altered by the interrupt */
- unsigned int dropped_frames;
-
-
-
- /* the CIP accumulator and continuity counter are properties
- of the DMA stream as a whole (not a single frame), so they
- are stored here in the video_card */
-
- unsigned long cip_accum;
- unsigned long cip_n, cip_d;
- unsigned int syt_offset;
- unsigned int continuity_counter;
-
- enum pal_or_ntsc pal_or_ntsc;
-
- /* redundant, but simplifies the code somewhat */
- unsigned int frame_size; /* in bytes */
-
- /* the isochronous channel to use, -1 if video card is inactive */
- int channel;
-
-
- /* physically contiguous packet ringbuffer for receive */
- struct dma_region packet_buf;
- unsigned long packet_buf_size;
-
- unsigned int current_packet;
- int first_frame; /* received first start frame marker? */
- enum modes mode;
-};
-
-/*
- if the video_card is not initialized, then the ONLY fields that are valid are:
- ohci
- open
- n_frames
-*/
-
-static inline int video_card_initialized(struct video_card *v)
-{
- return v->n_frames > 0;
-}
-
-static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
-static int do_dv1394_init_default(struct video_card *video);
-static void do_dv1394_shutdown(struct video_card *video, int free_user_buf);
-
-
-/* NTSC empty packet rate accurate to within 0.01%,
- calibrated against a Sony DSR-40 DVCAM deck */
-
-#define CIP_N_NTSC 68000000
-#define CIP_D_NTSC 1068000000
-
-#define CIP_N_PAL 1
-#define CIP_D_PAL 16
-
-#endif /* _DV_1394_PRIVATE_H */
-
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
deleted file mode 100644
index c5a031b79d03..000000000000
--- a/drivers/ieee1394/dv1394.c
+++ /dev/null
@@ -1,2584 +0,0 @@
-/*
- * dv1394.c - DV input/output over IEEE 1394 on OHCI chips
- * Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- * receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- * video1394.c - video driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- OVERVIEW
-
- I designed dv1394 as a "pipe" that you can use to shoot DV onto a
- FireWire bus. In transmission mode, dv1394 does the following:
-
- 1. accepts contiguous frames of DV data from user-space, via write()
- or mmap() (see dv1394.h for the complete API)
- 2. wraps IEC 61883 packets around the DV data, inserting
- empty synchronization packets as necessary
- 3. assigns accurate SYT timestamps to the outgoing packets
- 4. shoots them out using the OHCI card's IT DMA engine
-
- Thanks to Dan Dennedy, we now have a receive mode that does the following:
-
- 1. accepts raw IEC 61883 packets from the OHCI card
- 2. re-assembles the DV data payloads into contiguous frames,
- discarding empty packets
- 3. sends the DV data to user-space via read() or mmap()
-*/
-
-/*
- TODO:
-
- - tunable frame-drop behavior: either loop last frame, or halt transmission
-
- - use a scatter/gather buffer for DMA programs (f->descriptor_pool)
- so that we don't rely on allocating 64KB of contiguous kernel memory
- via pci_alloc_consistent()
-
- DONE:
- - during reception, better handling of dropped frames and continuity errors
- - during reception, prevent DMA from bypassing the irq tasklets
- - reduce irq rate during reception (1/250 packets).
- - add many more internal buffers during reception with scatter/gather dma.
- - add dbc (continuity) checking on receive, increment status.dropped_frames
- if not continuous.
- - restart IT DMA after a bus reset
- - safely obtain and release ISO Tx channels in cooperation with OHCI driver
- - map received DIF blocks to their proper location in DV frame (ensure
- recovery if dropped packet)
- - handle bus resets gracefully (OHCI card seems to take care of this itself(!))
- - do not allow resizing the user_buf once allocated; eliminate nuke_buffer_mappings
- - eliminated #ifdef DV1394_DEBUG_LEVEL by inventing macros debug_printk and irq_printk
- - added wmb() and mb() to places where PCI read/write ordering needs to be enforced
- - set video->id correctly
- - store video_cards in an array indexed by OHCI card ID, rather than a list
- - implement DMA context allocation to cooperate with other users of the OHCI
- - fix all XXX showstoppers
- - disable IR/IT DMA interrupts on shutdown
- - flush pci writes to the card by issuing a read
- - character device dispatching
- - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!)
- - keep all video_cards in a list (for open() via chardev), set file->private_data = video
- - dv1394_poll should indicate POLLIN when receiving buffers are available
- - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal
- - expose xmit and recv as separate devices (not exclusive)
- - expose NTSC and PAL as separate devices (can be overridden)
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/mutex.h>
-#include <linux/bitops.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/delay.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/string.h>
-#include <linux/compat.h>
-#include <linux/cdev.h>
-
-#include "dv1394.h"
-#include "dv1394-private.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "ohci1394.h"
-
-/* DEBUG LEVELS:
- 0 - no debugging messages
- 1 - some debugging messages, but none during DMA frame transmission
- 2 - lots of messages, including during DMA frame transmission
- (will cause underflows if your machine is too slow!)
-*/
-
-#define DV1394_DEBUG_LEVEL 0
-
-/* for debugging use ONLY: allow more than one open() of the device */
-/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */
-
-#if DV1394_DEBUG_LEVEL >= 2
-#define irq_printk( args... ) printk( args )
-#else
-#define irq_printk( args... ) do {} while (0)
-#endif
-
-#if DV1394_DEBUG_LEVEL >= 1
-#define debug_printk( args... ) printk( args)
-#else
-#define debug_printk( args... ) do {} while (0)
-#endif
-
-/* issue a dummy PCI read to force the preceding write
- to be posted to the PCI bus immediately */
-
-static inline void flush_pci_write(struct ti_ohci *ohci)
-{
- mb();
- reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static void it_tasklet_func(unsigned long data);
-static void ir_tasklet_func(unsigned long data);
-
-#ifdef CONFIG_COMPAT
-static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg);
-#endif
-
-/* GLOBAL DATA */
-
-/* list of all video_cards */
-static LIST_HEAD(dv1394_cards);
-static DEFINE_SPINLOCK(dv1394_cards_lock);
-
-/* translate from a struct file* to the corresponding struct video_card* */
-
-static inline struct video_card* file_to_video_card(struct file *file)
-{
- return file->private_data;
-}
-
-/*** FRAME METHODS *********************************************************/
-
-static void frame_reset(struct frame *f)
-{
- f->state = FRAME_CLEAR;
- f->done = 0;
- f->n_packets = 0;
- f->frame_begin_timestamp = NULL;
- f->assigned_timestamp = 0;
- f->cip_syt1 = NULL;
- f->cip_syt2 = NULL;
- f->mid_frame_timestamp = NULL;
- f->frame_end_timestamp = NULL;
- f->frame_end_branch = NULL;
-}
-
-static struct frame* frame_new(unsigned int frame_num, struct video_card *video)
-{
- struct frame *f = kmalloc(sizeof(*f), GFP_KERNEL);
- if (!f)
- return NULL;
-
- f->video = video;
- f->frame_num = frame_num;
-
- f->header_pool = pci_alloc_consistent(f->video->ohci->dev, PAGE_SIZE, &f->header_pool_dma);
- if (!f->header_pool) {
- printk(KERN_ERR "dv1394: failed to allocate CIP header pool\n");
- kfree(f);
- return NULL;
- }
-
- debug_printk("dv1394: frame_new: allocated CIP header pool at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
- (unsigned long) f->header_pool, (unsigned long) f->header_pool_dma, PAGE_SIZE);
-
- f->descriptor_pool_size = MAX_PACKETS * sizeof(struct DMA_descriptor_block);
- /* make it an even # of pages */
- f->descriptor_pool_size += PAGE_SIZE - (f->descriptor_pool_size%PAGE_SIZE);
-
- f->descriptor_pool = pci_alloc_consistent(f->video->ohci->dev,
- f->descriptor_pool_size,
- &f->descriptor_pool_dma);
- if (!f->descriptor_pool) {
- pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
- kfree(f);
- return NULL;
- }
-
- debug_printk("dv1394: frame_new: allocated DMA program memory at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
- (unsigned long) f->descriptor_pool, (unsigned long) f->descriptor_pool_dma, f->descriptor_pool_size);
-
- f->data = 0;
- frame_reset(f);
-
- return f;
-}
-
-static void frame_delete(struct frame *f)
-{
- pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
- pci_free_consistent(f->video->ohci->dev, f->descriptor_pool_size, f->descriptor_pool, f->descriptor_pool_dma);
- kfree(f);
-}
-
-
-
-
-/*
- frame_prepare() - build the DMA program for transmitting
-
- Frame_prepare() must be called OUTSIDE the video->spinlock.
- However, frame_prepare() must still be serialized, so
- it should be called WITH the video->mtx taken.
- */
-
-static void frame_prepare(struct video_card *video, unsigned int this_frame)
-{
- struct frame *f = video->frames[this_frame];
- int last_frame;
-
- struct DMA_descriptor_block *block;
- dma_addr_t block_dma;
- struct CIP_header *cip;
- dma_addr_t cip_dma;
-
- unsigned int n_descriptors, full_packets, packets_per_frame, payload_size;
-
- /* these flags denote packets that need special attention */
- int empty_packet, first_packet, last_packet, mid_packet;
-
- __le32 *branch_address, *last_branch_address = NULL;
- unsigned long data_p;
- int first_packet_empty = 0;
- u32 cycleTimer, ct_sec, ct_cyc, ct_off;
- unsigned long irq_flags;
-
- irq_printk("frame_prepare( %d ) ---------------------\n", this_frame);
-
- full_packets = 0;
-
-
-
- if (video->pal_or_ntsc == DV1394_PAL)
- packets_per_frame = DV1394_PAL_PACKETS_PER_FRAME;
- else
- packets_per_frame = DV1394_NTSC_PACKETS_PER_FRAME;
-
- while ( full_packets < packets_per_frame ) {
- empty_packet = first_packet = last_packet = mid_packet = 0;
-
- data_p = f->data + full_packets * 480;
-
- /************************************************/
- /* allocate a descriptor block and a CIP header */
- /************************************************/
-
- /* note: these should NOT cross a page boundary (DMA restriction) */
-
- if (f->n_packets >= MAX_PACKETS) {
- printk(KERN_ERR "dv1394: FATAL ERROR: max packet count exceeded\n");
- return;
- }
-
- /* the block surely won't cross a page boundary,
- since an even number of descriptor_blocks fit on a page */
- block = &(f->descriptor_pool[f->n_packets]);
-
- /* DMA address of the block = offset of block relative
- to the kernel base address of the descriptor pool
- + DMA base address of the descriptor pool */
- block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-
-
- /* the whole CIP pool fits on one page, so no worries about boundaries */
- if ( ((unsigned long) &(f->header_pool[f->n_packets]) - (unsigned long) f->header_pool)
- > PAGE_SIZE) {
- printk(KERN_ERR "dv1394: FATAL ERROR: no room to allocate CIP header\n");
- return;
- }
-
- cip = &(f->header_pool[f->n_packets]);
-
- /* DMA address of the CIP header = offset of cip
- relative to kernel base address of the header pool
- + DMA base address of the header pool */
- cip_dma = (unsigned long) cip % PAGE_SIZE + f->header_pool_dma;
-
- /* is this an empty packet? */
-
- if (video->cip_accum > (video->cip_d - video->cip_n)) {
- empty_packet = 1;
- payload_size = 8;
- video->cip_accum -= (video->cip_d - video->cip_n);
- } else {
- payload_size = 488;
- video->cip_accum += video->cip_n;
- }
-
- /* there are three important packets each frame:
-
- the first packet in the frame - we ask the card to record the timestamp when
- this packet is actually sent, so we can monitor
- how accurate our timestamps are. Also, the first
- packet serves as a semaphore to let us know that
- it's OK to free the *previous* frame's DMA buffer
-
- the last packet in the frame - this packet is used to detect buffer underflows.
- if this is the last ready frame, the last DMA block
- will have a branch back to the beginning of the frame
- (so that the card will re-send the frame on underflow).
- if this branch gets taken, we know that at least one
- frame has been dropped. When the next frame is ready,
- the branch is pointed to its first packet, and the
- semaphore is disabled.
-
- a "mid" packet slightly before the end of the frame - this packet should trigger
- an interrupt so we can go and assign a timestamp to the first packet
- in the next frame. We don't use the very last packet in the frame
- for this purpose, because that would leave very little time to set
- the timestamp before DMA starts on the next frame.
- */
-
- if (f->n_packets == 0) {
- first_packet = 1;
- } else if ( full_packets == (packets_per_frame-1) ) {
- last_packet = 1;
- } else if (f->n_packets == packets_per_frame) {
- mid_packet = 1;
- }
-
-
- /********************/
- /* setup CIP header */
- /********************/
-
- /* the timestamp will be written later from the
- mid-frame interrupt handler. For now we just
- store the address of the CIP header(s) that
- need a timestamp. */
-
- /* first packet in the frame needs a timestamp */
- if (first_packet) {
- f->cip_syt1 = cip;
- if (empty_packet)
- first_packet_empty = 1;
-
- } else if (first_packet_empty && (f->n_packets == 1) ) {
- /* if the first packet was empty, the second
- packet's CIP header also needs a timestamp */
- f->cip_syt2 = cip;
- }
-
- fill_cip_header(cip,
- /* the node ID number of the OHCI card */
- reg_read(video->ohci, OHCI1394_NodeID) & 0x3F,
- video->continuity_counter,
- video->pal_or_ntsc,
- 0xFFFF /* the timestamp is filled in later */);
-
- /* advance counter, only for full packets */
- if ( ! empty_packet )
- video->continuity_counter++;
-
- /******************************/
- /* setup DMA descriptor block */
- /******************************/
-
- /* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
- fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size);
-
- if (empty_packet) {
- /* second descriptor - OUTPUT_LAST for CIP header */
- fill_output_last( &(block->u.out.u.empty.ol),
-
- /* want completion status on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- /* want interrupts on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- sizeof(struct CIP_header), /* data size */
- cip_dma);
-
- if (first_packet)
- f->frame_begin_timestamp = &(block->u.out.u.empty.ol.q[3]);
- else if (mid_packet)
- f->mid_frame_timestamp = &(block->u.out.u.empty.ol.q[3]);
- else if (last_packet) {
- f->frame_end_timestamp = &(block->u.out.u.empty.ol.q[3]);
- f->frame_end_branch = &(block->u.out.u.empty.ol.q[2]);
- }
-
- branch_address = &(block->u.out.u.empty.ol.q[2]);
- n_descriptors = 3;
- if (first_packet)
- f->first_n_descriptors = n_descriptors;
-
- } else { /* full packet */
-
- /* second descriptor - OUTPUT_MORE for CIP header */
- fill_output_more( &(block->u.out.u.full.om),
- sizeof(struct CIP_header), /* data size */
- cip_dma);
-
-
- /* third (and possibly fourth) descriptor - for DV data */
- /* the 480-byte payload can cross a page boundary; if so,
- we need to split it into two DMA descriptors */
-
- /* does the 480-byte data payload cross a page boundary? */
- if ( (PAGE_SIZE- ((unsigned long)data_p % PAGE_SIZE) ) < 480 ) {
-
- /* page boundary crossed */
-
- fill_output_more( &(block->u.out.u.full.u.cross.om),
- /* data size - how much of data_p fits on the first page */
- PAGE_SIZE - (data_p % PAGE_SIZE),
-
- /* DMA address of data_p */
- dma_region_offset_to_bus(&video->dv_buf,
- data_p - (unsigned long) video->dv_buf.kvirt));
-
- fill_output_last( &(block->u.out.u.full.u.cross.ol),
-
- /* want completion status on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- /* want interrupt on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- /* data size - remaining portion of data_p */
- 480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
-
- /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
- dma_region_offset_to_bus(&video->dv_buf,
- data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt));
-
- if (first_packet)
- f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
- else if (mid_packet)
- f->mid_frame_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
- else if (last_packet) {
- f->frame_end_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
- f->frame_end_branch = &(block->u.out.u.full.u.cross.ol.q[2]);
- }
-
- branch_address = &(block->u.out.u.full.u.cross.ol.q[2]);
-
- n_descriptors = 5;
- if (first_packet)
- f->first_n_descriptors = n_descriptors;
-
- full_packets++;
-
- } else {
- /* fits on one page */
-
- fill_output_last( &(block->u.out.u.full.u.nocross.ol),
-
- /* want completion status on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- /* want interrupt on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- 480, /* data size (480 bytes of DV data) */
-
-
- /* DMA address of data_p */
- dma_region_offset_to_bus(&video->dv_buf,
- data_p - (unsigned long) video->dv_buf.kvirt));
-
- if (first_packet)
- f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
- else if (mid_packet)
- f->mid_frame_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
- else if (last_packet) {
- f->frame_end_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
- f->frame_end_branch = &(block->u.out.u.full.u.nocross.ol.q[2]);
- }
-
- branch_address = &(block->u.out.u.full.u.nocross.ol.q[2]);
-
- n_descriptors = 4;
- if (first_packet)
- f->first_n_descriptors = n_descriptors;
-
- full_packets++;
- }
- }
-
- /* link this descriptor block into the DMA program by filling in
- the branch address of the previous block */
-
- /* note: we are not linked into the active DMA chain yet */
-
- if (last_branch_address) {
- *(last_branch_address) = cpu_to_le32(block_dma | n_descriptors);
- }
-
- last_branch_address = branch_address;
-
-
- f->n_packets++;
-
- }
-
- /* when we first assemble a new frame, set the final branch
- to loop back up to the top */
- *(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
-
- /* make the latest version of this frame visible to the PCI card */
- dma_region_sync_for_device(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size);
-
- /* lock against DMA interrupt */
- spin_lock_irqsave(&video->spinlock, irq_flags);
-
- f->state = FRAME_READY;
-
- video->n_clear_frames--;
-
- last_frame = video->first_clear_frame - 1;
- if (last_frame == -1)
- last_frame = video->n_frames-1;
-
- video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
-
- irq_printk(" frame %d prepared, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n last=%d\n",
- this_frame, video->active_frame, video->n_clear_frames, video->first_clear_frame, last_frame);
-
- irq_printk(" begin_ts %08lx mid_ts %08lx end_ts %08lx end_br %08lx\n",
- (unsigned long) f->frame_begin_timestamp,
- (unsigned long) f->mid_frame_timestamp,
- (unsigned long) f->frame_end_timestamp,
- (unsigned long) f->frame_end_branch);
-
- if (video->active_frame != -1) {
-
- /* if DMA is already active, we are almost done */
- /* just link us onto the active DMA chain */
- if (video->frames[last_frame]->frame_end_branch) {
- u32 temp;
-
- /* point the previous frame's tail to this frame's head */
- *(video->frames[last_frame]->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
-
- /* this write MUST precede the next one, or we could silently drop frames */
- wmb();
-
- /* disable the want_status semaphore on the last packet */
- temp = le32_to_cpu(*(video->frames[last_frame]->frame_end_branch - 2));
- temp &= 0xF7CFFFFF;
- *(video->frames[last_frame]->frame_end_branch - 2) = cpu_to_le32(temp);
-
- /* flush these writes to memory ASAP */
- flush_pci_write(video->ohci);
-
- /* NOTE:
- ideally the writes should be "atomic": if
- the OHCI card reads the want_status flag in
- between them, we'll falsely report a
- dropped frame. Hopefully this window is too
- small to really matter, and the consequence
- is rather harmless. */
-
-
- irq_printk(" new frame %d linked onto DMA chain\n", this_frame);
-
- } else {
- printk(KERN_ERR "dv1394: last frame not ready???\n");
- }
-
- } else {
-
- u32 transmit_sec, transmit_cyc;
- u32 ts_cyc;
-
- /* DMA is stopped, so this is the very first frame */
- video->active_frame = this_frame;
-
- /* set CommandPtr to address and size of first descriptor block */
- reg_write(video->ohci, video->ohci_IsoXmitCommandPtr,
- video->frames[video->active_frame]->descriptor_pool_dma |
- f->first_n_descriptors);
-
- /* assign a timestamp based on the current cycle time...
- We'll tell the card to begin DMA 100 cycles from now,
- and assign a timestamp 103 cycles from now */
-
- cycleTimer = reg_read(video->ohci, OHCI1394_IsochronousCycleTimer);
-
- ct_sec = cycleTimer >> 25;
- ct_cyc = (cycleTimer >> 12) & 0x1FFF;
- ct_off = cycleTimer & 0xFFF;
-
- transmit_sec = ct_sec;
- transmit_cyc = ct_cyc + 100;
-
- transmit_sec += transmit_cyc/8000;
- transmit_cyc %= 8000;
-
- ts_cyc = transmit_cyc + 3;
- ts_cyc %= 8000;
-
- f->assigned_timestamp = (ts_cyc&0xF) << 12;
-
- /* now actually write the timestamp into the appropriate CIP headers */
- if (f->cip_syt1) {
- f->cip_syt1->b[6] = f->assigned_timestamp >> 8;
- f->cip_syt1->b[7] = f->assigned_timestamp & 0xFF;
- }
- if (f->cip_syt2) {
- f->cip_syt2->b[6] = f->assigned_timestamp >> 8;
- f->cip_syt2->b[7] = f->assigned_timestamp & 0xFF;
- }
-
- /* --- start DMA --- */
-
- /* clear all bits in ContextControl register */
-
- reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, 0xFFFFFFFF);
- wmb();
-
- /* the OHCI card has the ability to start ISO transmission on a
- particular cycle (start-on-cycle). This way we can ensure that
- the first DV frame will have an accurate timestamp.
-
- However, start-on-cycle only appears to work if the OHCI card
- is cycle master! Since the consequences of messing up the first
- timestamp are minimal*, just disable start-on-cycle for now.
-
- * my DV deck drops the first few frames before it "locks in;"
- so the first frame having an incorrect timestamp is inconsequential.
- */
-
-#if 0
- reg_write(video->ohci, video->ohci_IsoXmitContextControlSet,
- (1 << 31) /* enable start-on-cycle */
- | ( (transmit_sec & 0x3) << 29)
- | (transmit_cyc << 16));
- wmb();
-#endif
-
- video->dma_running = 1;
-
- /* set the 'run' bit */
- reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
- flush_pci_write(video->ohci);
-
- /* --- DMA should be running now --- */
-
- debug_printk(" Cycle = %4u ContextControl = %08x CmdPtr = %08x\n",
- (reg_read(video->ohci, OHCI1394_IsochronousCycleTimer) >> 12) & 0x1FFF,
- reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
- reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
-
- debug_printk(" DMA start - current cycle %4u, transmit cycle %4u (%2u), assigning ts cycle %2u\n",
- ct_cyc, transmit_cyc, transmit_cyc & 0xF, ts_cyc & 0xF);
-
-#if DV1394_DEBUG_LEVEL >= 2
- {
- /* check if DMA is really running */
- int i = 0;
- while (i < 20) {
- mb();
- mdelay(1);
- if (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) {
- printk("DMA ACTIVE after %d msec\n", i);
- break;
- }
- i++;
- }
-
- printk("set = %08x, cmdPtr = %08x\n",
- reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
- reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
- );
-
- if ( ! (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
- printk("DMA did NOT go active after 20ms, event = %x\n",
- reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & 0x1F);
- } else
- printk("DMA is RUNNING!\n");
- }
-#endif
-
- }
-
-
- spin_unlock_irqrestore(&video->spinlock, irq_flags);
-}
-
-
-
-/*** RECEIVE FUNCTIONS *****************************************************/
-
-/*
- frame method put_packet
-
- map and copy the packet data to its location in the frame
- based upon DIF section and sequence
-*/
-
-static void inline
-frame_put_packet (struct frame *f, struct packet *p)
-{
- int section_type = p->data[0] >> 5; /* section type is in bits 5 - 7 */
- int dif_sequence = p->data[1] >> 4; /* dif sequence number is in bits 4 - 7 */
- int dif_block = p->data[2];
-
- /* sanity check */
- if (dif_sequence > 11 || dif_block > 149) return;
-
- switch (section_type) {
- case 0: /* 1 Header block */
- memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
- break;
-
- case 1: /* 2 Subcode blocks */
- memcpy( (void *) f->data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p->data, 480);
- break;
-
- case 2: /* 3 VAUX blocks */
- memcpy( (void *) f->data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p->data, 480);
- break;
-
- case 3: /* 9 Audio blocks interleaved with video */
- memcpy( (void *) f->data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p->data, 480);
- break;
-
- case 4: /* 135 Video blocks interleaved with audio */
- memcpy( (void *) f->data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p->data, 480);
- break;
-
- default: /* we can not handle any other data */
- break;
- }
-}
-
-
-static void start_dma_receive(struct video_card *video)
-{
- if (video->first_run == 1) {
- video->first_run = 0;
-
- /* start DMA once all of the frames are READY */
- video->n_clear_frames = 0;
- video->first_clear_frame = -1;
- video->current_packet = 0;
- video->active_frame = 0;
-
- /* reset iso recv control register */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
- wmb();
-
- /* clear bufferFill, set isochHeader and speed (0=100) */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
-
- /* match on all tags, listen on channel */
- reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
-
- /* address and first descriptor block + Z=1 */
- reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,
- video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */
- wmb();
-
- video->dma_running = 1;
-
- /* run */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
- flush_pci_write(video->ohci);
-
- debug_printk("dv1394: DMA started\n");
-
-#if DV1394_DEBUG_LEVEL >= 2
- {
- int i;
-
- for (i = 0; i < 1000; ++i) {
- mdelay(1);
- if (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
- printk("DMA ACTIVE after %d msec\n", i);
- break;
- }
- }
- if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) {
- printk("DEAD, event = %x\n",
- reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
- } else
- printk("RUNNING!\n");
- }
-#endif
- } else if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) {
- debug_printk("DEAD, event = %x\n",
- reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-
- /* wake */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
- }
-}
-
-
-/*
- receive_packets() - build the DMA program for receiving
-*/
-
-static void receive_packets(struct video_card *video)
-{
- struct DMA_descriptor_block *block = NULL;
- dma_addr_t block_dma = 0;
- struct packet *data = NULL;
- dma_addr_t data_dma = 0;
- __le32 *last_branch_address = NULL;
- unsigned long irq_flags;
- int want_interrupt = 0;
- struct frame *f = NULL;
- int i, j;
-
- spin_lock_irqsave(&video->spinlock, irq_flags);
-
- for (j = 0; j < video->n_frames; j++) {
-
- /* connect frames */
- if (j > 0 && f != NULL && f->frame_end_branch != NULL)
- *(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */
-
- f = video->frames[j];
-
- for (i = 0; i < MAX_PACKETS; i++) {
- /* locate a descriptor block and packet from the buffer */
- block = &(f->descriptor_pool[i]);
- block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-
- data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i;
- data_dma = dma_region_offset_to_bus( &video->packet_buf,
- ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) );
-
- /* setup DMA descriptor block */
- want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1));
- fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma);
-
- /* link descriptors */
- last_branch_address = f->frame_end_branch;
-
- if (last_branch_address != NULL)
- *(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
-
- f->frame_end_branch = &(block->u.in.il.q[2]);
- }
-
- } /* next j */
-
- spin_unlock_irqrestore(&video->spinlock, irq_flags);
-
-}
-
-
-
-/*** MANAGEMENT FUNCTIONS **************************************************/
-
-static int do_dv1394_init(struct video_card *video, struct dv1394_init *init)
-{
- unsigned long flags, new_buf_size;
- int i;
- u64 chan_mask;
- int retval = -EINVAL;
-
- debug_printk("dv1394: initialising %d\n", video->id);
- if (init->api_version != DV1394_API_VERSION)
- return -EINVAL;
-
- /* first sanitize all the parameters */
- if ( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
- return -EINVAL;
-
- if ( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
- return -EINVAL;
-
- if ( (init->syt_offset == 0) || (init->syt_offset > 50) )
- /* default SYT offset is 3 cycles */
- init->syt_offset = 3;
-
- if (init->channel > 63)
- init->channel = 63;
-
- chan_mask = (u64)1 << init->channel;
-
- /* calculate what size DMA buffer is needed */
- if (init->format == DV1394_NTSC)
- new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames;
- else
- new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames;
-
- /* round up to PAGE_SIZE */
- if (new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
-
- /* don't allow the user to allocate the DMA buffer more than once */
- if (video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) {
- printk("dv1394: re-sizing the DMA buffer is not allowed\n");
- return -EINVAL;
- }
-
- /* shutdown the card if it's currently active */
- /* (the card should not be reset if the parameters are screwy) */
-
- do_dv1394_shutdown(video, 0);
-
- /* try to claim the ISO channel */
- spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
- if (video->ohci->ISO_channel_usage & chan_mask) {
- spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
- retval = -EBUSY;
- goto err;
- }
- video->ohci->ISO_channel_usage |= chan_mask;
- spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-
- video->channel = init->channel;
-
- /* initialize misc. fields of video */
- video->n_frames = init->n_frames;
- video->pal_or_ntsc = init->format;
-
- video->cip_accum = 0;
- video->continuity_counter = 0;
-
- video->active_frame = -1;
- video->first_clear_frame = 0;
- video->n_clear_frames = video->n_frames;
- video->dropped_frames = 0;
-
- video->write_off = 0;
-
- video->first_run = 1;
- video->current_packet = -1;
- video->first_frame = 0;
-
- if (video->pal_or_ntsc == DV1394_NTSC) {
- video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
- video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
- video->frame_size = DV1394_NTSC_FRAME_SIZE;
- } else {
- video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
- video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
- video->frame_size = DV1394_PAL_FRAME_SIZE;
- }
-
- video->syt_offset = init->syt_offset;
-
- /* find and claim DMA contexts on the OHCI card */
-
- if (video->ohci_it_ctx == -1) {
- ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT,
- it_tasklet_func, (unsigned long) video);
-
- if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) {
- printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
- retval = -EBUSY;
- goto err;
- }
-
- video->ohci_it_ctx = video->it_tasklet.context;
- debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
- }
-
- if (video->ohci_ir_ctx == -1) {
- ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,
- ir_tasklet_func, (unsigned long) video);
-
- if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) {
- printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
- retval = -EBUSY;
- goto err;
- }
- video->ohci_ir_ctx = video->ir_tasklet.context;
- debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
- }
-
- /* allocate struct frames */
- for (i = 0; i < init->n_frames; i++) {
- video->frames[i] = frame_new(i, video);
-
- if (!video->frames[i]) {
- printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
- retval = -ENOMEM;
- goto err;
- }
- }
-
- if (!video->dv_buf.kvirt) {
- /* allocate the ringbuffer */
- retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE);
- if (retval)
- goto err;
-
- video->dv_buf_size = new_buf_size;
-
- debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n",
- video->n_frames, video->dv_buf.n_pages,
- video->dv_buf.n_dma_pages, video->dv_buf_size);
- }
-
- /* set up the frame->data pointers */
- for (i = 0; i < video->n_frames; i++)
- video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size;
-
- if (!video->packet_buf.kvirt) {
- /* allocate packet buffer */
- video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS;
- if (video->packet_buf_size % PAGE_SIZE)
- video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE);
-
- retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size,
- video->ohci->dev, PCI_DMA_FROMDEVICE);
- if (retval)
- goto err;
-
- debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n",
- video->n_frames*MAX_PACKETS, video->packet_buf.n_pages,
- video->packet_buf.n_dma_pages, video->packet_buf_size);
- }
-
- /* set up register offsets for IT context */
- /* IT DMA context registers are spaced 16 bytes apart */
- video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx;
- video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx;
- video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx;
-
- /* enable interrupts for IT context */
- reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx));
- debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx);
-
- /* set up register offsets for IR context */
- /* IR DMA context registers are spaced 32 bytes apart */
- video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx;
- video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx;
- video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx;
- video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx;
-
- /* enable interrupts for IR context */
- reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) );
- debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx);
-
- return 0;
-
-err:
- do_dv1394_shutdown(video, 1);
- return retval;
-}
-
-/* if the user doesn't bother to call ioctl(INIT) before starting
- mmap() or read()/write(), just give him some default values */
-
-static int do_dv1394_init_default(struct video_card *video)
-{
- struct dv1394_init init;
-
- init.api_version = DV1394_API_VERSION;
- init.n_frames = DV1394_MAX_FRAMES / 4;
- init.channel = video->channel;
- init.format = video->pal_or_ntsc;
- init.cip_n = video->cip_n;
- init.cip_d = video->cip_d;
- init.syt_offset = video->syt_offset;
-
- return do_dv1394_init(video, &init);
-}
-
-/* do NOT call from interrupt context */
-static void stop_dma(struct video_card *video)
-{
- unsigned long flags;
- int i;
-
- /* no interrupts */
- spin_lock_irqsave(&video->spinlock, flags);
-
- video->dma_running = 0;
-
- if ( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) )
- goto out;
-
- /* stop DMA if in progress */
- if ( (video->active_frame != -1) ||
- (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
- (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) {
-
- /* clear the .run bits */
- reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
- reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
- flush_pci_write(video->ohci);
-
- video->active_frame = -1;
- video->first_run = 1;
-
- /* wait until DMA really stops */
- i = 0;
- while (i < 1000) {
-
- /* wait 0.1 millisecond */
- udelay(100);
-
- if ( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
- (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) {
- /* still active */
- debug_printk("dv1394: stop_dma: DMA not stopped yet\n" );
- mb();
- } else {
- debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);
- break;
- }
-
- i++;
- }
-
- if (i == 1000) {
- printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);
- }
- }
- else
- debug_printk("dv1394: stop_dma: already stopped.\n");
-
-out:
- spin_unlock_irqrestore(&video->spinlock, flags);
-}
-
-
-
-static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf)
-{
- int i;
-
- debug_printk("dv1394: shutdown...\n");
-
- /* stop DMA if in progress */
- stop_dma(video);
-
- /* release the DMA contexts */
- if (video->ohci_it_ctx != -1) {
- video->ohci_IsoXmitContextControlSet = 0;
- video->ohci_IsoXmitContextControlClear = 0;
- video->ohci_IsoXmitCommandPtr = 0;
-
- /* disable interrupts for IT context */
- reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx));
-
- /* remove tasklet */
- ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
- debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);
- video->ohci_it_ctx = -1;
- }
-
- if (video->ohci_ir_ctx != -1) {
- video->ohci_IsoRcvContextControlSet = 0;
- video->ohci_IsoRcvContextControlClear = 0;
- video->ohci_IsoRcvCommandPtr = 0;
- video->ohci_IsoRcvContextMatch = 0;
-
- /* disable interrupts for IR context */
- reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx));
-
- /* remove tasklet */
- ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
- debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx);
- video->ohci_ir_ctx = -1;
- }
-
- /* release the ISO channel */
- if (video->channel != -1) {
- u64 chan_mask;
- unsigned long flags;
-
- chan_mask = (u64)1 << video->channel;
-
- spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
- video->ohci->ISO_channel_usage &= ~(chan_mask);
- spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-
- video->channel = -1;
- }
-
- /* free the frame structs */
- for (i = 0; i < DV1394_MAX_FRAMES; i++) {
- if (video->frames[i])
- frame_delete(video->frames[i]);
- video->frames[i] = NULL;
- }
-
- video->n_frames = 0;
-
- /* we can't free the DMA buffer unless it is guaranteed that
- no more user-space mappings exist */
-
- if (free_dv_buf) {
- dma_region_free(&video->dv_buf);
- video->dv_buf_size = 0;
- }
-
- /* free packet buffer */
- dma_region_free(&video->packet_buf);
- video->packet_buf_size = 0;
-
- debug_printk("dv1394: shutdown OK\n");
-}
-
-/*
- **********************************
- *** MMAP() THEORY OF OPERATION ***
- **********************************
-
- The ringbuffer cannot be re-allocated or freed while
- a user program maintains a mapping of it. (note that a mapping
- can persist even after the device fd is closed!)
-
- So, only let the user process allocate the DMA buffer once.
- To resize or deallocate it, you must close the device file
- and open it again.
-
- Previously Dan M. hacked out a scheme that allowed the DMA
- buffer to change by forcefully unmapping it from the user's
- address space. It was prone to error because it's very hard to
- track all the places the buffer could have been mapped (we
- would have had to walk the vma list of every process in the
- system to be sure we found all the mappings!). Instead, we
- force the user to choose one buffer size and stick with
- it. This small sacrifice is worth the huge reduction in
- error-prone code in dv1394.
-*/
-
-static int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_card *video = file_to_video_card(file);
- int retval = -EINVAL;
-
- /*
- * We cannot use the blocking variant mutex_lock here because .mmap
- * is called with mmap_sem held, while .ioctl, .read, .write acquire
- * video->mtx and subsequently call copy_to/from_user which will
- * grab mmap_sem in case of a page fault.
- */
- if (!mutex_trylock(&video->mtx))
- return -EAGAIN;
-
- if ( ! video_card_initialized(video) ) {
- retval = do_dv1394_init_default(video);
- if (retval)
- goto out;
- }
-
- retval = dma_region_mmap(&video->dv_buf, file, vma);
-out:
- mutex_unlock(&video->mtx);
- return retval;
-}
-
-/*** DEVICE FILE INTERFACE *************************************************/
-
-/* no need to serialize, multiple threads OK */
-static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct video_card *video = file_to_video_card(file);
- unsigned int mask = 0;
- unsigned long flags;
-
- poll_wait(file, &video->waitq, wait);
-
- spin_lock_irqsave(&video->spinlock, flags);
- if ( video->n_frames == 0 ) {
-
- } else if ( video->active_frame == -1 ) {
- /* nothing going on */
- mask |= POLLOUT;
- } else {
- /* any clear/ready buffers? */
- if (video->n_clear_frames >0)
- mask |= POLLOUT | POLLIN;
- }
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- return mask;
-}
-
-static int dv1394_fasync(int fd, struct file *file, int on)
-{
- /* I just copied this code verbatim from Alan Cox's mouse driver example
- (Documentation/DocBook/) */
-
- struct video_card *video = file_to_video_card(file);
-
- return fasync_helper(fd, file, on, &video->fasync);
-}
-
-static ssize_t dv1394_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct video_card *video = file_to_video_card(file);
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- size_t cnt;
- unsigned long flags;
- int target_frame;
-
- /* serialize this to prevent multi-threaded mayhem */
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&video->mtx))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&video->mtx))
- return -ERESTARTSYS;
- }
-
- if ( !video_card_initialized(video) ) {
- ret = do_dv1394_init_default(video);
- if (ret) {
- mutex_unlock(&video->mtx);
- return ret;
- }
- }
-
- ret = 0;
- add_wait_queue(&video->waitq, &wait);
-
- while (count > 0) {
-
- /* must set TASK_INTERRUPTIBLE *before* checking for free
- buffers; otherwise we could miss a wakeup if the interrupt
- fires between the check and the schedule() */
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- target_frame = video->first_clear_frame;
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- if (video->frames[target_frame]->state == FRAME_CLEAR) {
-
- /* how much room is left in the target frame buffer */
- cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
-
- } else {
- /* buffer is already used */
- cnt = 0;
- }
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- /* no room left, gotta wait */
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
-
- schedule();
-
- continue; /* start over from 'while(count > 0)...' */
- }
-
- if (copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
-
- video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
-
- if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames))
- frame_prepare(video, target_frame);
- }
-
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
- mutex_unlock(&video->mtx);
- return ret;
-}
-
-
-static ssize_t dv1394_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct video_card *video = file_to_video_card(file);
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- size_t cnt;
- unsigned long flags;
- int target_frame;
-
- /* serialize this to prevent multi-threaded mayhem */
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&video->mtx))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&video->mtx))
- return -ERESTARTSYS;
- }
-
- if ( !video_card_initialized(video) ) {
- ret = do_dv1394_init_default(video);
- if (ret) {
- mutex_unlock(&video->mtx);
- return ret;
- }
- video->continuity_counter = -1;
-
- receive_packets(video);
-
- start_dma_receive(video);
- }
-
- ret = 0;
- add_wait_queue(&video->waitq, &wait);
-
- while (count > 0) {
-
- /* must set TASK_INTERRUPTIBLE *before* checking for free
- buffers; otherwise we could miss a wakeup if the interrupt
- fires between the check and the schedule() */
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- target_frame = video->first_clear_frame;
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- if (target_frame >= 0 &&
- video->n_clear_frames > 0 &&
- video->frames[target_frame]->state == FRAME_CLEAR) {
-
- /* how much room is left in the target frame buffer */
- cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
-
- } else {
- /* buffer is already used */
- cnt = 0;
- }
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- /* no room left, gotta wait */
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
-
- schedule();
-
- continue; /* start over from 'while(count > 0)...' */
- }
-
- if (copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
-
- video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
-
- if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) {
- spin_lock_irqsave(&video->spinlock, flags);
- video->n_clear_frames--;
- video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
- spin_unlock_irqrestore(&video->spinlock, flags);
- }
- }
-
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
- mutex_unlock(&video->mtx);
- return ret;
-}
-
-
-/*** DEVICE IOCTL INTERFACE ************************************************/
-
-static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct video_card *video = file_to_video_card(file);
- unsigned long flags;
- int ret = -EINVAL;
- void __user *argp = (void __user *)arg;
-
- DECLARE_WAITQUEUE(wait, current);
-
- /* serialize this to prevent multi-threaded mayhem */
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&video->mtx))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&video->mtx))
- return -ERESTARTSYS;
- }
-
- switch(cmd)
- {
- case DV1394_IOC_SUBMIT_FRAMES: {
- unsigned int n_submit;
-
- if ( !video_card_initialized(video) ) {
- ret = do_dv1394_init_default(video);
- if (ret)
- goto out;
- }
-
- n_submit = (unsigned int) arg;
-
- if (n_submit > video->n_frames) {
- ret = -EINVAL;
- goto out;
- }
-
- while (n_submit > 0) {
-
- add_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- /* wait until video->first_clear_frame is really CLEAR */
- while (video->frames[video->first_clear_frame]->state != FRAME_CLEAR) {
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- if (signal_pending(current)) {
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
- ret = -EINTR;
- goto out;
- }
-
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
- }
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
-
- frame_prepare(video, video->first_clear_frame);
-
- n_submit--;
- }
-
- ret = 0;
- break;
- }
-
- case DV1394_IOC_WAIT_FRAMES: {
- unsigned int n_wait;
-
- if ( !video_card_initialized(video) ) {
- ret = -EINVAL;
- goto out;
- }
-
- n_wait = (unsigned int) arg;
-
- /* since we re-run the last frame on underflow, we will
- never actually have n_frames clear frames; at most only
- n_frames - 1 */
-
- if (n_wait > (video->n_frames-1) ) {
- ret = -EINVAL;
- goto out;
- }
-
- add_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- while (video->n_clear_frames < n_wait) {
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- if (signal_pending(current)) {
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
- ret = -EINTR;
- goto out;
- }
-
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
- }
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
- ret = 0;
- break;
- }
-
- case DV1394_IOC_RECEIVE_FRAMES: {
- unsigned int n_recv;
-
- if ( !video_card_initialized(video) ) {
- ret = -EINVAL;
- goto out;
- }
-
- n_recv = (unsigned int) arg;
-
- /* at least one frame must be active */
- if (n_recv > (video->n_frames-1) ) {
- ret = -EINVAL;
- goto out;
- }
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- /* release the clear frames */
- video->n_clear_frames -= n_recv;
-
- /* advance the clear frame cursor */
- video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames;
-
- /* reset dropped_frames */
- video->dropped_frames = 0;
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- ret = 0;
- break;
- }
-
- case DV1394_IOC_START_RECEIVE: {
- if ( !video_card_initialized(video) ) {
- ret = do_dv1394_init_default(video);
- if (ret)
- goto out;
- }
-
- video->continuity_counter = -1;
-
- receive_packets(video);
-
- start_dma_receive(video);
-
- ret = 0;
- break;
- }
-
- case DV1394_IOC_INIT: {
- struct dv1394_init init;
- if (!argp) {
- ret = do_dv1394_init_default(video);
- } else {
- if (copy_from_user(&init, argp, sizeof(init))) {
- ret = -EFAULT;
- goto out;
- }
- ret = do_dv1394_init(video, &init);
- }
- break;
- }
-
- case DV1394_IOC_SHUTDOWN:
- do_dv1394_shutdown(video, 0);
- ret = 0;
- break;
-
-
- case DV1394_IOC_GET_STATUS: {
- struct dv1394_status status;
-
- if ( !video_card_initialized(video) ) {
- ret = -EINVAL;
- goto out;
- }
-
- status.init.api_version = DV1394_API_VERSION;
- status.init.channel = video->channel;
- status.init.n_frames = video->n_frames;
- status.init.format = video->pal_or_ntsc;
- status.init.cip_n = video->cip_n;
- status.init.cip_d = video->cip_d;
- status.init.syt_offset = video->syt_offset;
-
- status.first_clear_frame = video->first_clear_frame;
-
- /* the rest of the fields need to be locked against the interrupt */
- spin_lock_irqsave(&video->spinlock, flags);
-
- status.active_frame = video->active_frame;
- status.n_clear_frames = video->n_clear_frames;
-
- status.dropped_frames = video->dropped_frames;
-
- /* reset dropped_frames */
- video->dropped_frames = 0;
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- if (copy_to_user(argp, &status, sizeof(status))) {
- ret = -EFAULT;
- goto out;
- }
-
- ret = 0;
- break;
- }
-
- default:
- break;
- }
-
- out:
- mutex_unlock(&video->mtx);
- return ret;
-}
-
-/*** DEVICE FILE INTERFACE CONTINUED ***************************************/
-
-static int dv1394_open(struct inode *inode, struct file *file)
-{
- struct video_card *video = NULL;
-
- if (file->private_data) {
- video = file->private_data;
-
- } else {
- /* look up the card by ID */
- unsigned long flags;
- int idx = ieee1394_file_to_instance(file);
-
- spin_lock_irqsave(&dv1394_cards_lock, flags);
- if (!list_empty(&dv1394_cards)) {
- struct video_card *p;
- list_for_each_entry(p, &dv1394_cards, list) {
- if ((p->id) == idx) {
- video = p;
- break;
- }
- }
- }
- spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
- if (!video) {
- debug_printk("dv1394: OHCI card %d not found", idx);
- return -ENODEV;
- }
-
- file->private_data = (void*) video;
- }
-
-#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN
-
- if ( test_and_set_bit(0, &video->open) ) {
- /* video is already open by someone else */
- return -EBUSY;
- }
-
-#endif
-
- printk(KERN_INFO "%s: NOTE, the dv1394 interface is unsupported "
- "and will not be available in the new firewire driver stack. "
- "Try libraw1394 based programs instead.\n", current->comm);
-
- return nonseekable_open(inode, file);
-}
-
-
-static int dv1394_release(struct inode *inode, struct file *file)
-{
- struct video_card *video = file_to_video_card(file);
-
- /* OK to free the DMA buffer, no more mappings can exist */
- do_dv1394_shutdown(video, 1);
-
- /* give someone else a turn */
- clear_bit(0, &video->open);
-
- return 0;
-}
-
-
-/*** DEVICE DRIVER HANDLERS ************************************************/
-
-static void it_tasklet_func(unsigned long data)
-{
- int wake = 0;
- struct video_card *video = (struct video_card*) data;
-
- spin_lock(&video->spinlock);
-
- if (!video->dma_running)
- goto out;
-
- irq_printk("ContextControl = %08x, CommandPtr = %08x\n",
- reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
- reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
- );
-
-
- if ( (video->ohci_it_ctx != -1) &&
- (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
-
- struct frame *f;
- unsigned int frame, i;
-
-
- if (video->active_frame == -1)
- frame = 0;
- else
- frame = video->active_frame;
-
- /* check all the DMA-able frames */
- for (i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) {
-
- irq_printk("IRQ checking frame %d...", frame);
- f = video->frames[frame];
- if (f->state != FRAME_READY) {
- irq_printk("clear, skipping\n");
- /* we don't own this frame */
- continue;
- }
-
- irq_printk("DMA\n");
-
- /* check the frame begin semaphore to see if we can free the previous frame */
- if ( *(f->frame_begin_timestamp) ) {
- int prev_frame;
- struct frame *prev_f;
-
-
-
- /* don't reset, need this later *(f->frame_begin_timestamp) = 0; */
- irq_printk(" BEGIN\n");
-
- prev_frame = frame - 1;
- if (prev_frame == -1)
- prev_frame += video->n_frames;
- prev_f = video->frames[prev_frame];
-
- /* make sure we can actually garbage collect
- this frame */
- if ( (prev_f->state == FRAME_READY) &&
- prev_f->done && (!f->done) )
- {
- frame_reset(prev_f);
- video->n_clear_frames++;
- wake = 1;
- video->active_frame = frame;
-
- irq_printk(" BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame);
- } else {
- irq_printk(" BEGIN - can't free yet\n");
- }
-
- f->done = 1;
- }
-
-
- /* see if we need to set the timestamp for the next frame */
- if ( *(f->mid_frame_timestamp) ) {
- struct frame *next_frame;
- u32 begin_ts, ts_cyc, ts_off;
-
- *(f->mid_frame_timestamp) = 0;
-
- begin_ts = le32_to_cpu(*(f->frame_begin_timestamp));
-
- irq_printk(" MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
- begin_ts & 0x1FFF, begin_ts & 0xF,
- f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF);
-
- /* prepare next frame and assign timestamp */
- next_frame = video->frames[ (frame+1) % video->n_frames ];
-
- if (next_frame->state == FRAME_READY) {
- irq_printk(" MIDDLE - next frame is ready, good\n");
- } else {
- debug_printk("dv1394: Underflow! At least one frame has been dropped.\n");
- next_frame = f;
- }
-
- /* set the timestamp to the timestamp of the last frame sent,
- plus the length of the last frame sent, plus the syt latency */
- ts_cyc = begin_ts & 0xF;
- /* advance one frame, plus syt latency (typically 2-3) */
- ts_cyc += f->n_packets + video->syt_offset ;
-
- ts_off = 0;
-
- ts_cyc += ts_off/3072;
- ts_off %= 3072;
-
- next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off;
- if (next_frame->cip_syt1) {
- next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8;
- next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF;
- }
- if (next_frame->cip_syt2) {
- next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8;
- next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF;
- }
-
- }
-
- /* see if the frame looped */
- if ( *(f->frame_end_timestamp) ) {
-
- *(f->frame_end_timestamp) = 0;
-
- debug_printk(" END - the frame looped at least once\n");
-
- video->dropped_frames++;
- }
-
- } /* for (each frame) */
- }
-
- if (wake) {
- kill_fasync(&video->fasync, SIGIO, POLL_OUT);
-
- /* wake readers/writers/ioctl'ers */
- wake_up_interruptible(&video->waitq);
- }
-
-out:
- spin_unlock(&video->spinlock);
-}
-
-static void ir_tasklet_func(unsigned long data)
-{
- int wake = 0;
- struct video_card *video = (struct video_card*) data;
-
- spin_lock(&video->spinlock);
-
- if (!video->dma_running)
- goto out;
-
- if ( (video->ohci_ir_ctx != -1) &&
- (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) {
-
- int sof=0; /* start-of-frame flag */
- struct frame *f;
- u16 packet_length;
- int i, dbc=0;
- struct DMA_descriptor_block *block = NULL;
- u16 xferstatus;
-
- int next_i, prev_i;
- struct DMA_descriptor_block *next = NULL;
- dma_addr_t next_dma = 0;
- struct DMA_descriptor_block *prev = NULL;
-
- /* loop over all descriptors in all frames */
- for (i = 0; i < video->n_frames*MAX_PACKETS; i++) {
- struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet);
-
- /* make sure we are seeing the latest changes to p */
- dma_region_sync_for_cpu(&video->packet_buf,
- (unsigned long) p - (unsigned long) video->packet_buf.kvirt,
- sizeof(struct packet));
-
- packet_length = le16_to_cpu(p->data_length);
-
- /* get the descriptor based on packet_buffer cursor */
- f = video->frames[video->current_packet / MAX_PACKETS];
- block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]);
- xferstatus = le32_to_cpu(block->u.in.il.q[3]) >> 16;
- xferstatus &= 0x1F;
- irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) );
-
- /* get the current frame */
- f = video->frames[video->active_frame];
-
- /* exclude empty packet */
- if (packet_length > 8 && xferstatus == 0x11) {
- /* check for start of frame */
- /* DRD> Changed to check section type ([0]>>5==0)
- and dif sequence ([1]>>4==0) */
- sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0);
-
- dbc = (int) (p->cip_h1 >> 24);
- if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) )
- {
- printk(KERN_WARNING "dv1394: discontinuity detected, dropping all frames\n" );
- video->dropped_frames += video->n_clear_frames + 1;
- video->first_frame = 0;
- video->n_clear_frames = 0;
- video->first_clear_frame = -1;
- }
- video->continuity_counter = dbc;
-
- if (!video->first_frame) {
- if (sof) {
- video->first_frame = 1;
- }
-
- } else if (sof) {
- /* close current frame */
- frame_reset(f); /* f->state = STATE_CLEAR */
- video->n_clear_frames++;
- if (video->n_clear_frames > video->n_frames) {
- video->dropped_frames++;
- printk(KERN_WARNING "dv1394: dropped a frame during reception\n" );
- video->n_clear_frames = video->n_frames-1;
- video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
- }
- if (video->first_clear_frame == -1)
- video->first_clear_frame = video->active_frame;
-
- /* get the next frame */
- video->active_frame = (video->active_frame + 1) % video->n_frames;
- f = video->frames[video->active_frame];
- irq_printk(" frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
- video->active_frame, video->n_clear_frames, video->first_clear_frame);
- }
- if (video->first_frame) {
- if (sof) {
- /* open next frame */
- f->state = FRAME_READY;
- }
-
- /* copy to buffer */
- if (f->n_packets > (video->frame_size / 480)) {
- printk(KERN_ERR "frame buffer overflow during receive\n");
- }
-
- frame_put_packet(f, p);
-
- } /* first_frame */
- }
-
- /* stop, end of ready packets */
- else if (xferstatus == 0) {
- break;
- }
-
- /* reset xferStatus & resCount */
- block->u.in.il.q[3] = cpu_to_le32(512);
-
- /* terminate dma chain at this (next) packet */
- next_i = video->current_packet;
- f = video->frames[next_i / MAX_PACKETS];
- next = &(f->descriptor_pool[next_i % MAX_PACKETS]);
- next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
- next->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */
- next->u.in.il.q[2] = cpu_to_le32(0); /* disable branch */
-
- /* link previous to next */
- prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1);
- f = video->frames[prev_i / MAX_PACKETS];
- prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]);
- if (prev_i % (MAX_PACKETS/2)) {
- prev->u.in.il.q[0] &= ~cpu_to_le32(3 << 20); /* no interrupt */
- } else {
- prev->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */
- }
- prev->u.in.il.q[2] = cpu_to_le32(next_dma | 1); /* set Z=1 */
- wmb();
-
- /* wake up DMA in case it fell asleep */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-
- /* advance packet_buffer cursor */
- video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames);
-
- } /* for all packets */
-
- wake = 1; /* why the hell not? */
-
- } /* receive interrupt */
-
- if (wake) {
- kill_fasync(&video->fasync, SIGIO, POLL_IN);
-
- /* wake readers/writers/ioctl'ers */
- wake_up_interruptible(&video->waitq);
- }
-
-out:
- spin_unlock(&video->spinlock);
-}
-
-static struct cdev dv1394_cdev;
-static const struct file_operations dv1394_fops=
-{
- .owner = THIS_MODULE,
- .poll = dv1394_poll,
- .unlocked_ioctl = dv1394_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = dv1394_compat_ioctl,
-#endif
- .mmap = dv1394_mmap,
- .open = dv1394_open,
- .write = dv1394_write,
- .read = dv1394_read,
- .release = dv1394_release,
- .fasync = dv1394_fasync,
- .llseek = no_llseek,
-};
-
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id dv1394_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = AVC_SW_VERSION_ENTRY & 0xffffff
- },
- { }
-};
-
-MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver dv1394_driver = {
- .name = "dv1394",
-};
-
-
-/*** IEEE1394 HPSB CALLBACKS ***********************************************/
-
-static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode)
-{
- struct video_card *video;
- unsigned long flags;
- int i;
-
- video = kzalloc(sizeof(*video), GFP_KERNEL);
- if (!video) {
- printk(KERN_ERR "dv1394: cannot allocate video_card\n");
- return -1;
- }
-
- video->ohci = ohci;
- /* lower 2 bits of id indicate which of four "plugs"
- per host */
- video->id = ohci->host->id << 2;
- if (format == DV1394_NTSC)
- video->id |= mode;
- else
- video->id |= 2 + mode;
-
- video->ohci_it_ctx = -1;
- video->ohci_ir_ctx = -1;
-
- video->ohci_IsoXmitContextControlSet = 0;
- video->ohci_IsoXmitContextControlClear = 0;
- video->ohci_IsoXmitCommandPtr = 0;
-
- video->ohci_IsoRcvContextControlSet = 0;
- video->ohci_IsoRcvContextControlClear = 0;
- video->ohci_IsoRcvCommandPtr = 0;
- video->ohci_IsoRcvContextMatch = 0;
-
- video->n_frames = 0; /* flag that video is not initialized */
- video->channel = 63; /* default to broadcast channel */
- video->active_frame = -1;
-
- /* initialize the following */
- video->pal_or_ntsc = format;
- video->cip_n = 0; /* 0 = use builtin default */
- video->cip_d = 0;
- video->syt_offset = 0;
- video->mode = mode;
-
- for (i = 0; i < DV1394_MAX_FRAMES; i++)
- video->frames[i] = NULL;
-
- dma_region_init(&video->dv_buf);
- video->dv_buf_size = 0;
- dma_region_init(&video->packet_buf);
- video->packet_buf_size = 0;
-
- clear_bit(0, &video->open);
- spin_lock_init(&video->spinlock);
- video->dma_running = 0;
- mutex_init(&video->mtx);
- init_waitqueue_head(&video->waitq);
- video->fasync = NULL;
-
- spin_lock_irqsave(&dv1394_cards_lock, flags);
- INIT_LIST_HEAD(&video->list);
- list_add_tail(&video->list, &dv1394_cards);
- spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
- debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id);
- return 0;
-}
-
-static void dv1394_remove_host(struct hpsb_host *host)
-{
- struct video_card *video, *tmp_video;
- unsigned long flags;
- int found_ohci_card = 0;
-
- do {
- video = NULL;
- spin_lock_irqsave(&dv1394_cards_lock, flags);
- list_for_each_entry(tmp_video, &dv1394_cards, list) {
- if ((tmp_video->id >> 2) == host->id) {
- list_del(&tmp_video->list);
- video = tmp_video;
- found_ohci_card = 1;
- break;
- }
- }
- spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
- if (video) {
- do_dv1394_shutdown(video, 1);
- kfree(video);
- }
- } while (video);
-
- if (found_ohci_card)
- device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2)));
-}
-
-static void dv1394_add_host(struct hpsb_host *host)
-{
- struct ti_ohci *ohci;
- int id = host->id;
-
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
-
- ohci = (struct ti_ohci *)host->hostdata;
-
- device_create(hpsb_protocol_class, NULL,
- MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)),
- NULL, "dv1394-%d", id);
-
- dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
- dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
- dv1394_init(ohci, DV1394_PAL, MODE_RECEIVE);
- dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT);
-}
-
-
-/* Bus reset handler. In the event of a bus reset, we may need to
- re-start the DMA contexts - otherwise the user program would
- end up waiting forever.
-*/
-
-static void dv1394_host_reset(struct hpsb_host *host)
-{
- struct video_card *video = NULL, *tmp_vid;
- unsigned long flags;
-
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
-
- /* find the corresponding video_cards */
- spin_lock_irqsave(&dv1394_cards_lock, flags);
- list_for_each_entry(tmp_vid, &dv1394_cards, list) {
- if ((tmp_vid->id >> 2) == host->id) {
- video = tmp_vid;
- break;
- }
- }
- spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
- if (!video)
- return;
-
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- if (!video->dma_running)
- goto out;
-
- /* check IT context */
- if (video->ohci_it_ctx != -1) {
- u32 ctx;
-
- ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet);
-
- /* if (RUN but not ACTIVE) */
- if ( (ctx & (1<<15)) &&
- !(ctx & (1<<10)) ) {
-
- debug_printk("dv1394: IT context stopped due to bus reset; waking it up\n");
-
- /* to be safe, assume a frame has been dropped. User-space programs
- should handle this condition like an underflow. */
- video->dropped_frames++;
-
- /* for some reason you must clear, then re-set the RUN bit to restart DMA */
-
- /* clear RUN */
- reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
- flush_pci_write(video->ohci);
-
- /* set RUN */
- reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 15));
- flush_pci_write(video->ohci);
-
- /* set the WAKE bit (just in case; this isn't strictly necessary) */
- reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 12));
- flush_pci_write(video->ohci);
-
- irq_printk("dv1394: AFTER IT restart ctx 0x%08x ptr 0x%08x\n",
- reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
- reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
- }
- }
-
- /* check IR context */
- if (video->ohci_ir_ctx != -1) {
- u32 ctx;
-
- ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet);
-
- /* if (RUN but not ACTIVE) */
- if ( (ctx & (1<<15)) &&
- !(ctx & (1<<10)) ) {
-
- debug_printk("dv1394: IR context stopped due to bus reset; waking it up\n");
-
- /* to be safe, assume a frame has been dropped. User-space programs
- should handle this condition like an overflow. */
- video->dropped_frames++;
-
- /* for some reason you must clear, then re-set the RUN bit to restart DMA */
- /* XXX this doesn't work for me, I can't get IR DMA to restart :[ */
-
- /* clear RUN */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
- flush_pci_write(video->ohci);
-
- /* set RUN */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 15));
- flush_pci_write(video->ohci);
-
- /* set the WAKE bit (just in case; this isn't strictly necessary) */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
- flush_pci_write(video->ohci);
-
- irq_printk("dv1394: AFTER IR restart ctx 0x%08x ptr 0x%08x\n",
- reg_read(video->ohci, video->ohci_IsoRcvContextControlSet),
- reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
- }
- }
-
-out:
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- /* wake readers/writers/ioctl'ers */
- wake_up_interruptible(&video->waitq);
-}
-
-static struct hpsb_highlevel dv1394_highlevel = {
- .name = "dv1394",
- .add_host = dv1394_add_host,
- .remove_host = dv1394_remove_host,
- .host_reset = dv1394_host_reset,
-};
-
-#ifdef CONFIG_COMPAT
-
-#define DV1394_IOC32_INIT _IOW('#', 0x06, struct dv1394_init32)
-#define DV1394_IOC32_GET_STATUS _IOR('#', 0x0c, struct dv1394_status32)
-
-struct dv1394_init32 {
- u32 api_version;
- u32 channel;
- u32 n_frames;
- u32 format;
- u32 cip_n;
- u32 cip_d;
- u32 syt_offset;
-};
-
-struct dv1394_status32 {
- struct dv1394_init32 init;
- s32 active_frame;
- u32 first_clear_frame;
- u32 n_clear_frames;
- u32 dropped_frames;
-};
-
-/* RED-PEN: this should use compat_alloc_userspace instead */
-
-static int handle_dv1394_init(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct dv1394_init32 dv32;
- struct dv1394_init dv;
- mm_segment_t old_fs;
- int ret;
-
- if (file->f_op->unlocked_ioctl != dv1394_ioctl)
- return -EFAULT;
-
- if (copy_from_user(&dv32, (void __user *)arg, sizeof(dv32)))
- return -EFAULT;
-
- dv.api_version = dv32.api_version;
- dv.channel = dv32.channel;
- dv.n_frames = dv32.n_frames;
- dv.format = dv32.format;
- dv.cip_n = (unsigned long)dv32.cip_n;
- dv.cip_d = (unsigned long)dv32.cip_d;
- dv.syt_offset = dv32.syt_offset;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = dv1394_ioctl(file, DV1394_IOC_INIT, (unsigned long)&dv);
- set_fs(old_fs);
-
- return ret;
-}
-
-static int handle_dv1394_get_status(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct dv1394_status32 dv32;
- struct dv1394_status dv;
- mm_segment_t old_fs;
- int ret;
-
- if (file->f_op->unlocked_ioctl != dv1394_ioctl)
- return -EFAULT;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = dv1394_ioctl(file, DV1394_IOC_GET_STATUS, (unsigned long)&dv);
- set_fs(old_fs);
-
- if (!ret) {
- dv32.init.api_version = dv.init.api_version;
- dv32.init.channel = dv.init.channel;
- dv32.init.n_frames = dv.init.n_frames;
- dv32.init.format = dv.init.format;
- dv32.init.cip_n = (u32)dv.init.cip_n;
- dv32.init.cip_d = (u32)dv.init.cip_d;
- dv32.init.syt_offset = dv.init.syt_offset;
- dv32.active_frame = dv.active_frame;
- dv32.first_clear_frame = dv.first_clear_frame;
- dv32.n_clear_frames = dv.n_clear_frames;
- dv32.dropped_frames = dv.dropped_frames;
-
- if (copy_to_user((struct dv1394_status32 __user *)arg, &dv32, sizeof(dv32)))
- ret = -EFAULT;
- }
-
- return ret;
-}
-
-
-
-static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- switch (cmd) {
- case DV1394_IOC_SHUTDOWN:
- case DV1394_IOC_SUBMIT_FRAMES:
- case DV1394_IOC_WAIT_FRAMES:
- case DV1394_IOC_RECEIVE_FRAMES:
- case DV1394_IOC_START_RECEIVE:
- return dv1394_ioctl(file, cmd, arg);
-
- case DV1394_IOC32_INIT:
- return handle_dv1394_init(file, cmd, arg);
- case DV1394_IOC32_GET_STATUS:
- return handle_dv1394_get_status(file, cmd, arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-#endif /* CONFIG_COMPAT */
-
-
-/*** KERNEL MODULE HANDLERS ************************************************/
-
-MODULE_AUTHOR("Dan Maas <dmaas@dcine.com>, Dan Dennedy <dan@dennedy.org>");
-MODULE_DESCRIPTION("driver for DV input/output on OHCI board");
-MODULE_SUPPORTED_DEVICE("dv1394");
-MODULE_LICENSE("GPL");
-
-static void __exit dv1394_exit_module(void)
-{
- hpsb_unregister_protocol(&dv1394_driver);
- hpsb_unregister_highlevel(&dv1394_highlevel);
- cdev_del(&dv1394_cdev);
-}
-
-static int __init dv1394_init_module(void)
-{
- int ret;
-
- cdev_init(&dv1394_cdev, &dv1394_fops);
- dv1394_cdev.owner = THIS_MODULE;
- ret = cdev_add(&dv1394_cdev, IEEE1394_DV1394_DEV, 16);
- if (ret) {
- printk(KERN_ERR "dv1394: unable to register character device\n");
- return ret;
- }
-
- hpsb_register_highlevel(&dv1394_highlevel);
-
- ret = hpsb_register_protocol(&dv1394_driver);
- if (ret) {
- printk(KERN_ERR "dv1394: failed to register protocol\n");
- hpsb_unregister_highlevel(&dv1394_highlevel);
- cdev_del(&dv1394_cdev);
- return ret;
- }
-
- return 0;
-}
-
-module_init(dv1394_init_module);
-module_exit(dv1394_exit_module);
diff --git a/drivers/ieee1394/dv1394.h b/drivers/ieee1394/dv1394.h
deleted file mode 100644
index 5807f5289810..000000000000
--- a/drivers/ieee1394/dv1394.h
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * dv1394.h - DV input/output over IEEE 1394 on OHCI chips
- * Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- * receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- * video1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _DV_1394_H
-#define _DV_1394_H
-
-/* This is the public user-space interface. Try not to break it. */
-
-#define DV1394_API_VERSION 0x20011127
-
-/* ********************
- ** **
- ** DV1394 API **
- ** **
- ********************
-
- There are two methods of operating the DV1394 DV output device.
-
- 1)
-
- The simplest is an interface based on write(): simply write
- full DV frames of data to the device, and they will be transmitted
- as quickly as possible. The FD may be set for non-blocking I/O,
- in which case you can use select() or poll() to wait for output
- buffer space.
-
- To set the DV output parameters (e.g. whether you want NTSC or PAL
- video), use the DV1394_INIT ioctl, passing in the parameters you
- want in a struct dv1394_init.
-
- Example 1:
- To play a raw .DV file: cat foo.DV > /dev/dv1394
- (cat will use write() internally)
-
- Example 2:
- static struct dv1394_init init = {
- 0x63, (broadcast channel)
- 4, (four-frame ringbuffer)
- DV1394_NTSC, (send NTSC video)
- 0, 0 (default empty packet rate)
- }
-
- ioctl(fd, DV1394_INIT, &init);
-
- while (1) {
- read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE );
- write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE );
- }
-
- 2)
-
- For more control over buffering, and to avoid unnecessary copies
- of the DV data, you can use the more sophisticated the mmap() interface.
- First, call the DV1394_INIT ioctl to specify your parameters,
- including the number of frames in the ringbuffer. Then, calling mmap()
- on the dv1394 device will give you direct access to the ringbuffer
- from which the DV card reads your frame data.
-
- The ringbuffer is simply one large, contiguous region of memory
- containing two or more frames of packed DV data. Each frame of DV data
- is 120000 bytes (NTSC) or 144000 bytes (PAL).
-
- Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES
- ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl
- or select()/poll() to wait until the frames are transmitted. Next, you'll
- need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer
- frames are clear (ready to be filled with new DV data). Finally, use
- DV1394_SUBMIT_FRAMES again to send the new data to the DV output.
-
-
- Example: here is what a four-frame ringbuffer might look like
- during DV transmission:
-
-
- frame 0 frame 1 frame 2 frame 3
-
- *--------------------------------------*
- | CLEAR | DV data | DV data | CLEAR |
- *--------------------------------------*
- <ACTIVE>
-
- transmission goes in this direction --->>>
-
-
- The DV hardware is currently transmitting the data in frame 1.
- Once frame 1 is finished, it will automatically transmit frame 2.
- (if frame 2 finishes before frame 3 is submitted, the device
- will continue to transmit frame 2, and will increase the dropped_frames
- counter each time it repeats the transmission).
-
-
- If you called DV1394_GET_STATUS at this instant, you would
- receive the following values:
-
- n_frames = 4
- active_frame = 1
- first_clear_frame = 3
- n_clear_frames = 2
-
- At this point, you should write new DV data into frame 3 and optionally
- frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
- it may transmit the new frames.
-
- ERROR HANDLING
-
- An error (buffer underflow/overflow or a break in the DV stream due
- to a 1394 bus reset) can be detected by checking the dropped_frames
- field of struct dv1394_status (obtained through the
- DV1394_GET_STATUS ioctl).
-
- The best way to recover from such an error is to re-initialize
- dv1394, either by using the DV1394_INIT ioctl call, or closing the
- file descriptor and opening it again. (note that you must unmap all
- ringbuffer mappings when closing the file descriptor, or else
- dv1394 will still be considered 'in use').
-
- MAIN LOOP
-
- For maximum efficiency and robustness against bus errors, you are
- advised to model the main loop of your application after the
- following pseudo-code example:
-
- (checks of system call return values omitted for brevity; always
- check return values in your code!)
-
- while ( frames left ) {
-
- struct pollfd *pfd = ...;
-
- pfd->fd = dv1394_fd;
- pfd->revents = 0;
- pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive)
-
- (add other sources of I/O here)
-
- poll(pfd, 1, -1); (or select(); add a timeout if you want)
-
- if (pfd->revents) {
- struct dv1394_status status;
-
- ioctl(dv1394_fd, DV1394_GET_STATUS, &status);
-
- if (status.dropped_frames > 0) {
- reset_dv1394();
- } else {
- for (int i = 0; i < status.n_clear_frames; i++) {
- copy_DV_frame();
- }
- }
- }
- }
-
- where copy_DV_frame() reads or writes on the dv1394 file descriptor
- (read/write mode) or copies data to/from the mmap ringbuffer and
- then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new
- frames are availble (mmap mode).
-
- reset_dv1394() is called in the event of a buffer
- underflow/overflow or a halt in the DV stream (e.g. due to a 1394
- bus reset). To guarantee recovery from the error, this function
- should close the dv1394 file descriptor (and munmap() all
- ringbuffer mappings, if you are using them), then re-open the
- dv1394 device (and re-map the ringbuffer).
-
-*/
-
-
-/* maximum number of frames in the ringbuffer */
-#define DV1394_MAX_FRAMES 32
-
-/* number of *full* isochronous packets per DV frame */
-#define DV1394_NTSC_PACKETS_PER_FRAME 250
-#define DV1394_PAL_PACKETS_PER_FRAME 300
-
-/* size of one frame's worth of DV data, in bytes */
-#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME)
-#define DV1394_PAL_FRAME_SIZE (480 * DV1394_PAL_PACKETS_PER_FRAME)
-
-
-/* ioctl() commands */
-#include "ieee1394-ioctl.h"
-
-
-enum pal_or_ntsc {
- DV1394_NTSC = 0,
- DV1394_PAL
-};
-
-
-
-
-/* this is the argument to DV1394_INIT */
-struct dv1394_init {
- /* DV1394_API_VERSION */
- unsigned int api_version;
-
- /* isochronous transmission channel to use */
- unsigned int channel;
-
- /* number of frames in the ringbuffer. Must be at least 2
- and at most DV1394_MAX_FRAMES. */
- unsigned int n_frames;
-
- /* send/receive PAL or NTSC video format */
- enum pal_or_ntsc format;
-
- /* the following are used only for transmission */
-
- /* set these to zero unless you want a
- non-default empty packet rate (see below) */
- unsigned long cip_n;
- unsigned long cip_d;
-
- /* set this to zero unless you want a
- non-default SYT cycle offset (default = 3 cycles) */
- unsigned int syt_offset;
-};
-
-/* NOTE: you may only allocate the DV frame ringbuffer once each time
- you open the dv1394 device. DV1394_INIT will fail if you call it a
- second time with different 'n_frames' or 'format' arguments (which
- would imply a different size for the ringbuffer). If you need a
- different buffer size, simply close and re-open the device, then
- initialize it with your new settings. */
-
-/* Q: What are cip_n and cip_d? */
-
-/*
- A: DV video streams do not utilize 100% of the potential bandwidth offered
- by IEEE 1394 (FireWire). To achieve the correct rate of data transmission,
- DV devices must periodically insert empty packets into the 1394 data stream.
- Typically there is one empty packet per 14-16 data-carrying packets.
-
- Some DV devices will accept a wide range of empty packet rates, while others
- require a precise rate. If the dv1394 driver produces empty packets at
- a rate that your device does not accept, you may see ugly patterns on the
- DV output, or even no output at all.
-
- The default empty packet insertion rate seems to work for many people; if
- your DV output is stable, you can simply ignore this discussion. However,
- we have exposed the empty packet rate as a parameter to support devices that
- do not work with the default rate.
-
- The decision to insert an empty packet is made with a numerator/denominator
- algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D.
- You can alter the empty packet rate by passing non-zero values for cip_n
- and cip_d to the INIT ioctl.
-
- */
-
-
-
-struct dv1394_status {
- /* this embedded init struct returns the current dv1394
- parameters in use */
- struct dv1394_init init;
-
- /* the ringbuffer frame that is currently being
- displayed. (-1 if the device is not transmitting anything) */
- int active_frame;
-
- /* index of the first buffer (ahead of active_frame) that
- is ready to be filled with data */
- unsigned int first_clear_frame;
-
- /* how many buffers, including first_clear_buffer, are
- ready to be filled with data */
- unsigned int n_clear_frames;
-
- /* how many times the DV stream has underflowed, overflowed,
- or otherwise encountered an error, since the previous call
- to DV1394_GET_STATUS */
- unsigned int dropped_frames;
-
- /* N.B. The dropped_frames counter is only a lower bound on the actual
- number of dropped frames, with the special case that if dropped_frames
- is zero, then it is guaranteed that NO frames have been dropped
- since the last call to DV1394_GET_STATUS.
- */
-};
-
-
-#endif /* _DV_1394_H */
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
deleted file mode 100644
index 63403822330e..000000000000
--- a/drivers/ieee1394/eth1394.c
+++ /dev/null
@@ -1,1720 +0,0 @@
-/*
- * eth1394.c -- IPv4 driver for Linux IEEE-1394 Subsystem
- *
- * Copyright (C) 2001-2003 Ben Collins <bcollins@debian.org>
- * 2000 Bonin Franck <boninf@free.fr>
- * 2003 Steve Kinneberg <kinnebergsteve@acmsystems.com>
- *
- * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
- *
- * 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.
- */
-
-/*
- * This driver intends to support RFC 2734, which describes a method for
- * transporting IPv4 datagrams over IEEE-1394 serial busses.
- *
- * TODO:
- * RFC 2734 related:
- * - Add MCAP. Limited Multicast exists only to 224.0.0.1 and 224.0.0.2.
- *
- * Non-RFC 2734 related:
- * - Handle fragmented skb's coming from the networking layer.
- * - Move generic GASP reception to core 1394 code
- * - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead
- * - Stability improvements
- * - Performance enhancements
- * - Consider garbage collecting old partial datagrams after X amount of time
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/workqueue.h>
-
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/if_arp.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/delay.h>
-#include <asm/unaligned.h>
-#include <net/arp.h>
-
-#include "config_roms.h"
-#include "csr1212.h"
-#include "eth1394.h"
-#include "highlevel.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "iso.h"
-#include "nodemgr.h"
-
-#define ETH1394_PRINT_G(level, fmt, args...) \
- printk(level "%s: " fmt, driver_name, ## args)
-
-#define ETH1394_PRINT(level, dev_name, fmt, args...) \
- printk(level "%s: %s: " fmt, driver_name, dev_name, ## args)
-
-struct fragment_info {
- struct list_head list;
- int offset;
- int len;
-};
-
-struct partial_datagram {
- struct list_head list;
- u16 dgl;
- u16 dg_size;
- __be16 ether_type;
- struct sk_buff *skb;
- char *pbuf;
- struct list_head frag_info;
-};
-
-struct pdg_list {
- struct list_head list; /* partial datagram list per node */
- unsigned int sz; /* partial datagram list size per node */
- spinlock_t lock; /* partial datagram lock */
-};
-
-struct eth1394_host_info {
- struct hpsb_host *host;
- struct net_device *dev;
-};
-
-struct eth1394_node_ref {
- struct unit_directory *ud;
- struct list_head list;
-};
-
-struct eth1394_node_info {
- u16 maxpayload; /* max payload */
- u8 sspd; /* max speed */
- u64 fifo; /* FIFO address */
- struct pdg_list pdg; /* partial RX datagram lists */
- int dgl; /* outgoing datagram label */
-};
-
-static const char driver_name[] = "eth1394";
-
-static struct kmem_cache *packet_task_cache;
-
-static struct hpsb_highlevel eth1394_highlevel;
-
-/* Use common.lf to determine header len */
-static const int hdr_type_len[] = {
- sizeof(struct eth1394_uf_hdr),
- sizeof(struct eth1394_ff_hdr),
- sizeof(struct eth1394_sf_hdr),
- sizeof(struct eth1394_sf_hdr)
-};
-
-static const u16 eth1394_speedto_maxpayload[] = {
-/* S100, S200, S400, S800, S1600, S3200 */
- 512, 1024, 2048, 4096, 4096, 4096
-};
-
-MODULE_AUTHOR("Ben Collins (bcollins@debian.org)");
-MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
-MODULE_LICENSE("GPL");
-
-/*
- * The max_partial_datagrams parameter is the maximum number of fragmented
- * datagrams per node that eth1394 will keep in memory. Providing an upper
- * bound allows us to limit the amount of memory that partial datagrams
- * consume in the event that some partial datagrams are never completed.
- */
-static int max_partial_datagrams = 25;
-module_param(max_partial_datagrams, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(max_partial_datagrams,
- "Maximum number of partially received fragmented datagrams "
- "(default = 25).");
-
-
-static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *daddr,
- const void *saddr, unsigned len);
-static int ether1394_rebuild_header(struct sk_buff *skb);
-static int ether1394_header_parse(const struct sk_buff *skb,
- unsigned char *haddr);
-static int ether1394_header_cache(const struct neighbour *neigh,
- struct hh_cache *hh);
-static void ether1394_header_cache_update(struct hh_cache *hh,
- const struct net_device *dev,
- const unsigned char *haddr);
-static netdev_tx_t ether1394_tx(struct sk_buff *skb,
- struct net_device *dev);
-static void ether1394_iso(struct hpsb_iso *iso);
-
-static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
- quadlet_t *data, u64 addr, size_t len, u16 flags);
-static void ether1394_add_host(struct hpsb_host *host);
-static void ether1394_remove_host(struct hpsb_host *host);
-static void ether1394_host_reset(struct hpsb_host *host);
-
-/* Function for incoming 1394 packets */
-static const struct hpsb_address_ops addr_ops = {
- .write = ether1394_write,
-};
-
-/* Ieee1394 highlevel driver functions */
-static struct hpsb_highlevel eth1394_highlevel = {
- .name = driver_name,
- .add_host = ether1394_add_host,
- .remove_host = ether1394_remove_host,
- .host_reset = ether1394_host_reset,
-};
-
-static int ether1394_recv_init(struct eth1394_priv *priv)
-{
- unsigned int iso_buf_size;
-
- /* FIXME: rawiso limits us to PAGE_SIZE */
- iso_buf_size = min((unsigned int)PAGE_SIZE,
- 2 * (1U << (priv->host->csr.max_rec + 1)));
-
- priv->iso = hpsb_iso_recv_init(priv->host,
- ETHER1394_GASP_BUFFERS * iso_buf_size,
- ETHER1394_GASP_BUFFERS,
- priv->broadcast_channel,
- HPSB_ISO_DMA_PACKET_PER_BUFFER,
- 1, ether1394_iso);
- if (priv->iso == NULL) {
- ETH1394_PRINT_G(KERN_ERR, "Failed to allocate IR context\n");
- priv->bc_state = ETHER1394_BC_ERROR;
- return -EAGAIN;
- }
-
- if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
- priv->bc_state = ETHER1394_BC_STOPPED;
- else
- priv->bc_state = ETHER1394_BC_RUNNING;
- return 0;
-}
-
-/* This is called after an "ifup" */
-static int ether1394_open(struct net_device *dev)
-{
- struct eth1394_priv *priv = netdev_priv(dev);
- int ret;
-
- if (priv->bc_state == ETHER1394_BC_ERROR) {
- ret = ether1394_recv_init(priv);
- if (ret)
- return ret;
- }
- netif_start_queue(dev);
- return 0;
-}
-
-/* This is called after an "ifdown" */
-static int ether1394_stop(struct net_device *dev)
-{
- /* flush priv->wake */
- flush_scheduled_work();
-
- netif_stop_queue(dev);
- return 0;
-}
-
-/* FIXME: What to do if we timeout? I think a host reset is probably in order,
- * so that's what we do. Should we increment the stat counters too? */
-static void ether1394_tx_timeout(struct net_device *dev)
-{
- struct hpsb_host *host =
- ((struct eth1394_priv *)netdev_priv(dev))->host;
-
- ETH1394_PRINT(KERN_ERR, dev->name, "Timeout, resetting host\n");
- ether1394_host_reset(host);
-}
-
-static inline int ether1394_max_mtu(struct hpsb_host* host)
-{
- return (1 << (host->csr.max_rec + 1))
- - sizeof(union eth1394_hdr) - ETHER1394_GASP_OVERHEAD;
-}
-
-static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
-{
- int max_mtu;
-
- if (new_mtu < 68)
- return -EINVAL;
-
- max_mtu = ether1394_max_mtu(
- ((struct eth1394_priv *)netdev_priv(dev))->host);
- if (new_mtu > max_mtu) {
- ETH1394_PRINT(KERN_INFO, dev->name,
- "Local node constrains MTU to %d\n", max_mtu);
- return -ERANGE;
- }
-
- dev->mtu = new_mtu;
- return 0;
-}
-
-static void purge_partial_datagram(struct list_head *old)
-{
- struct partial_datagram *pd;
- struct list_head *lh, *n;
- struct fragment_info *fi;
-
- pd = list_entry(old, struct partial_datagram, list);
-
- list_for_each_safe(lh, n, &pd->frag_info) {
- fi = list_entry(lh, struct fragment_info, list);
- list_del(lh);
- kfree(fi);
- }
- list_del(old);
- kfree_skb(pd->skb);
- kfree(pd);
-}
-
-/******************************************
- * 1394 bus activity functions
- ******************************************/
-
-static struct eth1394_node_ref *eth1394_find_node(struct list_head *inl,
- struct unit_directory *ud)
-{
- struct eth1394_node_ref *node;
-
- list_for_each_entry(node, inl, list)
- if (node->ud == ud)
- return node;
-
- return NULL;
-}
-
-static struct eth1394_node_ref *eth1394_find_node_guid(struct list_head *inl,
- u64 guid)
-{
- struct eth1394_node_ref *node;
-
- list_for_each_entry(node, inl, list)
- if (node->ud->ne->guid == guid)
- return node;
-
- return NULL;
-}
-
-static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl,
- nodeid_t nodeid)
-{
- struct eth1394_node_ref *node;
-
- list_for_each_entry(node, inl, list)
- if (node->ud->ne->nodeid == nodeid)
- return node;
-
- return NULL;
-}
-
-static int eth1394_new_node(struct eth1394_host_info *hi,
- struct unit_directory *ud)
-{
- struct eth1394_priv *priv;
- struct eth1394_node_ref *new_node;
- struct eth1394_node_info *node_info;
-
- new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
- if (!new_node)
- return -ENOMEM;
-
- node_info = kmalloc(sizeof(*node_info), GFP_KERNEL);
- if (!node_info) {
- kfree(new_node);
- return -ENOMEM;
- }
-
- spin_lock_init(&node_info->pdg.lock);
- INIT_LIST_HEAD(&node_info->pdg.list);
- node_info->pdg.sz = 0;
- node_info->fifo = CSR1212_INVALID_ADDR_SPACE;
-
- dev_set_drvdata(&ud->device, node_info);
- new_node->ud = ud;
-
- priv = netdev_priv(hi->dev);
- list_add_tail(&new_node->list, &priv->ip_node_list);
- return 0;
-}
-
-static int eth1394_probe(struct device *dev)
-{
- struct unit_directory *ud;
- struct eth1394_host_info *hi;
-
- ud = container_of(dev, struct unit_directory, device);
- hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
- if (!hi)
- return -ENOENT;
-
- return eth1394_new_node(hi, ud);
-}
-
-static int eth1394_remove(struct device *dev)
-{
- struct unit_directory *ud;
- struct eth1394_host_info *hi;
- struct eth1394_priv *priv;
- struct eth1394_node_ref *old_node;
- struct eth1394_node_info *node_info;
- struct list_head *lh, *n;
- unsigned long flags;
-
- ud = container_of(dev, struct unit_directory, device);
- hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
- if (!hi)
- return -ENOENT;
-
- priv = netdev_priv(hi->dev);
-
- old_node = eth1394_find_node(&priv->ip_node_list, ud);
- if (!old_node)
- return 0;
-
- list_del(&old_node->list);
- kfree(old_node);
-
- node_info = dev_get_drvdata(&ud->device);
-
- spin_lock_irqsave(&node_info->pdg.lock, flags);
- /* The partial datagram list should be empty, but we'll just
- * make sure anyway... */
- list_for_each_safe(lh, n, &node_info->pdg.list)
- purge_partial_datagram(lh);
- spin_unlock_irqrestore(&node_info->pdg.lock, flags);
-
- kfree(node_info);
- dev_set_drvdata(&ud->device, NULL);
- return 0;
-}
-
-static int eth1394_update(struct unit_directory *ud)
-{
- struct eth1394_host_info *hi;
- struct eth1394_priv *priv;
- struct eth1394_node_ref *node;
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
- if (!hi)
- return -ENOENT;
-
- priv = netdev_priv(hi->dev);
- node = eth1394_find_node(&priv->ip_node_list, ud);
- if (node)
- return 0;
-
- return eth1394_new_node(hi, ud);
-}
-
-static const struct ieee1394_device_id eth1394_id_table[] = {
- {
- .match_flags = (IEEE1394_MATCH_SPECIFIER_ID |
- IEEE1394_MATCH_VERSION),
- .specifier_id = ETHER1394_GASP_SPECIFIER_ID,
- .version = ETHER1394_GASP_VERSION,
- },
- {}
-};
-
-MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table);
-
-static struct hpsb_protocol_driver eth1394_proto_driver = {
- .name = driver_name,
- .id_table = eth1394_id_table,
- .update = eth1394_update,
- .driver = {
- .probe = eth1394_probe,
- .remove = eth1394_remove,
- },
-};
-
-static void ether1394_reset_priv(struct net_device *dev, int set_mtu)
-{
- unsigned long flags;
- int i;
- struct eth1394_priv *priv = netdev_priv(dev);
- struct hpsb_host *host = priv->host;
- u64 guid = get_unaligned((u64 *)&(host->csr.rom->bus_info_data[3]));
- int max_speed = IEEE1394_SPEED_MAX;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- memset(priv->ud_list, 0, sizeof(priv->ud_list));
- priv->bc_maxpayload = 512;
-
- /* Determine speed limit */
- /* FIXME: This is broken for nodes with link speed < PHY speed,
- * and it is suboptimal for S200B...S800B hardware.
- * The result of nodemgr's speed probe should be used somehow. */
- for (i = 0; i < host->node_count; i++) {
- /* take care of S100B...S400B PHY ports */
- if (host->speed[i] == SELFID_SPEED_UNKNOWN) {
- max_speed = IEEE1394_SPEED_100;
- break;
- }
- if (max_speed > host->speed[i])
- max_speed = host->speed[i];
- }
- priv->bc_sspd = max_speed;
-
- if (set_mtu) {
- /* Use the RFC 2734 default 1500 octets or the maximum payload
- * as initial MTU */
- dev->mtu = min(1500, ether1394_max_mtu(host));
-
- /* Set our hardware address while we're at it */
- memcpy(dev->dev_addr, &guid, sizeof(u64));
- memset(dev->broadcast, 0xff, sizeof(u64));
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static const struct header_ops ether1394_header_ops = {
- .create = ether1394_header,
- .rebuild = ether1394_rebuild_header,
- .cache = ether1394_header_cache,
- .cache_update = ether1394_header_cache_update,
- .parse = ether1394_header_parse,
-};
-
-static const struct net_device_ops ether1394_netdev_ops = {
- .ndo_open = ether1394_open,
- .ndo_stop = ether1394_stop,
- .ndo_start_xmit = ether1394_tx,
- .ndo_tx_timeout = ether1394_tx_timeout,
- .ndo_change_mtu = ether1394_change_mtu,
-};
-
-static void ether1394_init_dev(struct net_device *dev)
-{
-
- dev->header_ops = &ether1394_header_ops;
- dev->netdev_ops = &ether1394_netdev_ops;
-
- dev->watchdog_timeo = ETHER1394_TIMEOUT;
- dev->flags = IFF_BROADCAST | IFF_MULTICAST;
- dev->features = NETIF_F_HIGHDMA;
- dev->addr_len = ETH1394_ALEN;
- dev->hard_header_len = ETH1394_HLEN;
- dev->type = ARPHRD_IEEE1394;
-
- /* FIXME: This value was copied from ether_setup(). Is it too much? */
- dev->tx_queue_len = 1000;
-}
-
-/*
- * Wake the queue up after commonly encountered transmit failure conditions are
- * hopefully over. Currently only tlabel exhaustion is accounted for.
- */
-static void ether1394_wake_queue(struct work_struct *work)
-{
- struct eth1394_priv *priv;
- struct hpsb_packet *packet;
-
- priv = container_of(work, struct eth1394_priv, wake);
- packet = hpsb_alloc_packet(0);
-
- /* This is really bad, but unjam the queue anyway. */
- if (!packet)
- goto out;
-
- packet->host = priv->host;
- packet->node_id = priv->wake_node;
- /*
- * A transaction label is all we really want. If we get one, it almost
- * always means we can get a lot more because the ieee1394 core recycled
- * a whole batch of tlabels, at last.
- */
- if (hpsb_get_tlabel(packet) == 0)
- hpsb_free_tlabel(packet);
-
- hpsb_free_packet(packet);
-out:
- netif_wake_queue(priv->wake_dev);
-}
-
-/*
- * This function is called every time a card is found. It is generally called
- * when the module is installed. This is where we add all of our ethernet
- * devices. One for each host.
- */
-static void ether1394_add_host(struct hpsb_host *host)
-{
- struct eth1394_host_info *hi = NULL;
- struct net_device *dev = NULL;
- struct eth1394_priv *priv;
- u64 fifo_addr;
-
- if (hpsb_config_rom_ip1394_add(host) != 0) {
- ETH1394_PRINT_G(KERN_ERR, "Can't add IP-over-1394 ROM entry\n");
- return;
- }
-
- fifo_addr = hpsb_allocate_and_register_addrspace(
- &eth1394_highlevel, host, &addr_ops,
- ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN,
- CSR1212_INVALID_ADDR_SPACE, CSR1212_INVALID_ADDR_SPACE);
- if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
- ETH1394_PRINT_G(KERN_ERR, "Cannot register CSR space\n");
- hpsb_config_rom_ip1394_remove(host);
- return;
- }
-
- dev = alloc_netdev(sizeof(*priv), "eth%d", ether1394_init_dev);
- if (dev == NULL) {
- ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
- goto out;
- }
-
- SET_NETDEV_DEV(dev, &host->device);
-
- priv = netdev_priv(dev);
- INIT_LIST_HEAD(&priv->ip_node_list);
- spin_lock_init(&priv->lock);
- priv->host = host;
- priv->local_fifo = fifo_addr;
- INIT_WORK(&priv->wake, ether1394_wake_queue);
- priv->wake_dev = dev;
-
- hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
- if (hi == NULL) {
- ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
- goto out;
- }
-
- ether1394_reset_priv(dev, 1);
-
- if (register_netdev(dev)) {
- ETH1394_PRINT_G(KERN_ERR, "Cannot register the driver\n");
- goto out;
- }
-
- ETH1394_PRINT(KERN_INFO, dev->name, "IPv4 over IEEE 1394 (fw-host%d)\n",
- host->id);
-
- hi->host = host;
- hi->dev = dev;
-
- /* Ignore validity in hopes that it will be set in the future. It'll
- * be checked when the eth device is opened. */
- priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
-
- ether1394_recv_init(priv);
- return;
-out:
- if (dev)
- free_netdev(dev);
- if (hi)
- hpsb_destroy_hostinfo(&eth1394_highlevel, host);
- hpsb_unregister_addrspace(&eth1394_highlevel, host, fifo_addr);
- hpsb_config_rom_ip1394_remove(host);
-}
-
-/* Remove a card from our list */
-static void ether1394_remove_host(struct hpsb_host *host)
-{
- struct eth1394_host_info *hi;
- struct eth1394_priv *priv;
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
- if (!hi)
- return;
- priv = netdev_priv(hi->dev);
- hpsb_unregister_addrspace(&eth1394_highlevel, host, priv->local_fifo);
- hpsb_config_rom_ip1394_remove(host);
- if (priv->iso)
- hpsb_iso_shutdown(priv->iso);
- unregister_netdev(hi->dev);
- free_netdev(hi->dev);
-}
-
-/* A bus reset happened */
-static void ether1394_host_reset(struct hpsb_host *host)
-{
- struct eth1394_host_info *hi;
- struct eth1394_priv *priv;
- struct net_device *dev;
- struct list_head *lh, *n;
- struct eth1394_node_ref *node;
- struct eth1394_node_info *node_info;
- unsigned long flags;
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-
- /* This can happen for hosts that we don't use */
- if (!hi)
- return;
-
- dev = hi->dev;
- priv = netdev_priv(dev);
-
- /* Reset our private host data, but not our MTU */
- netif_stop_queue(dev);
- ether1394_reset_priv(dev, 0);
-
- list_for_each_entry(node, &priv->ip_node_list, list) {
- node_info = dev_get_drvdata(&node->ud->device);
-
- spin_lock_irqsave(&node_info->pdg.lock, flags);
-
- list_for_each_safe(lh, n, &node_info->pdg.list)
- purge_partial_datagram(lh);
-
- INIT_LIST_HEAD(&(node_info->pdg.list));
- node_info->pdg.sz = 0;
-
- spin_unlock_irqrestore(&node_info->pdg.lock, flags);
- }
-
- netif_wake_queue(dev);
-}
-
-/******************************************
- * HW Header net device functions
- ******************************************/
-/* These functions have been adapted from net/ethernet/eth.c */
-
-/* Create a fake MAC header for an arbitrary protocol layer.
- * saddr=NULL means use device source address
- * daddr=NULL means leave destination address (eg unresolved arp). */
-static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *daddr,
- const void *saddr, unsigned len)
-{
- struct eth1394hdr *eth =
- (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
-
- eth->h_proto = htons(type);
-
- if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
- memset(eth->h_dest, 0, dev->addr_len);
- return dev->hard_header_len;
- }
-
- if (daddr) {
- memcpy(eth->h_dest, daddr, dev->addr_len);
- return dev->hard_header_len;
- }
-
- return -dev->hard_header_len;
-}
-
-/* Rebuild the faked MAC header. This is called after an ARP
- * (or in future other address resolution) has completed on this
- * sk_buff. We now let ARP fill in the other fields.
- *
- * This routine CANNOT use cached dst->neigh!
- * Really, it is used only when dst->neigh is wrong.
- */
-static int ether1394_rebuild_header(struct sk_buff *skb)
-{
- struct eth1394hdr *eth = (struct eth1394hdr *)skb->data;
-
- if (eth->h_proto == htons(ETH_P_IP))
- return arp_find((unsigned char *)&eth->h_dest, skb);
-
- ETH1394_PRINT(KERN_DEBUG, skb->dev->name,
- "unable to resolve type %04x addresses\n",
- ntohs(eth->h_proto));
- return 0;
-}
-
-static int ether1394_header_parse(const struct sk_buff *skb,
- unsigned char *haddr)
-{
- memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN);
- return ETH1394_ALEN;
-}
-
-static int ether1394_header_cache(const struct neighbour *neigh,
- struct hh_cache *hh)
-{
- __be16 type = hh->hh_type;
- struct net_device *dev = neigh->dev;
- struct eth1394hdr *eth =
- (struct eth1394hdr *)((u8 *)hh->hh_data + 16 - ETH1394_HLEN);
-
- if (type == htons(ETH_P_802_3))
- return -1;
-
- eth->h_proto = type;
- memcpy(eth->h_dest, neigh->ha, dev->addr_len);
-
- hh->hh_len = ETH1394_HLEN;
- return 0;
-}
-
-/* Called by Address Resolution module to notify changes in address. */
-static void ether1394_header_cache_update(struct hh_cache *hh,
- const struct net_device *dev,
- const unsigned char * haddr)
-{
- memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len);
-}
-
-/******************************************
- * Datagram reception code
- ******************************************/
-
-/* Copied from net/ethernet/eth.c */
-static __be16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
- struct eth1394hdr *eth;
- unsigned char *rawp;
-
- skb_reset_mac_header(skb);
- skb_pull(skb, ETH1394_HLEN);
- eth = eth1394_hdr(skb);
-
- if (*eth->h_dest & 1) {
- if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len) == 0)
- skb->pkt_type = PACKET_BROADCAST;
-#if 0
- else
- skb->pkt_type = PACKET_MULTICAST;
-#endif
- } else {
- if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len))
- skb->pkt_type = PACKET_OTHERHOST;
- }
-
- if (ntohs(eth->h_proto) >= 1536)
- return eth->h_proto;
-
- rawp = skb->data;
-
- if (*(unsigned short *)rawp == 0xFFFF)
- return htons(ETH_P_802_3);
-
- return htons(ETH_P_802_2);
-}
-
-/* Parse an encapsulated IP1394 header into an ethernet frame packet.
- * We also perform ARP translation here, if need be. */
-static __be16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
- nodeid_t srcid, nodeid_t destid,
- __be16 ether_type)
-{
- struct eth1394_priv *priv = netdev_priv(dev);
- __be64 dest_hw;
- __be16 ret = 0;
-
- /* Setup our hw addresses. We use these to build the ethernet header. */
- if (destid == (LOCAL_BUS | ALL_NODES))
- dest_hw = ~cpu_to_be64(0); /* broadcast */
- else
- dest_hw = cpu_to_be64((u64)priv->host->csr.guid_hi << 32 |
- priv->host->csr.guid_lo);
-
- /* If this is an ARP packet, convert it. First, we want to make
- * use of some of the fields, since they tell us a little bit
- * about the sending machine. */
- if (ether_type == htons(ETH_P_ARP)) {
- struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
- struct arphdr *arp = (struct arphdr *)skb->data;
- unsigned char *arp_ptr = (unsigned char *)(arp + 1);
- u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 |
- ntohl(arp1394->fifo_lo);
- u8 max_rec = min(priv->host->csr.max_rec,
- (u8)(arp1394->max_rec));
- int sspd = arp1394->sspd;
- u16 maxpayload;
- struct eth1394_node_ref *node;
- struct eth1394_node_info *node_info;
- __be64 guid;
-
- /* Sanity check. MacOSX seems to be sending us 131 in this
- * field (atleast on my Panther G5). Not sure why. */
- if (sspd > 5 || sspd < 0)
- sspd = 0;
-
- maxpayload = min(eth1394_speedto_maxpayload[sspd],
- (u16)(1 << (max_rec + 1)));
-
- guid = get_unaligned(&arp1394->s_uniq_id);
- node = eth1394_find_node_guid(&priv->ip_node_list,
- be64_to_cpu(guid));
- if (!node)
- return cpu_to_be16(0);
-
- node_info = dev_get_drvdata(&node->ud->device);
-
- /* Update our speed/payload/fifo_offset table */
- node_info->maxpayload = maxpayload;
- node_info->sspd = sspd;
- node_info->fifo = fifo_addr;
-
- /* Now that we're done with the 1394 specific stuff, we'll
- * need to alter some of the data. Believe it or not, all
- * that needs to be done is sender_IP_address needs to be
- * moved, the destination hardware address get stuffed
- * in and the hardware address length set to 8.
- *
- * IMPORTANT: The code below overwrites 1394 specific data
- * needed above so keep the munging of the data for the
- * higher level IP stack last. */
-
- arp->ar_hln = 8;
- arp_ptr += arp->ar_hln; /* skip over sender unique id */
- *(u32 *)arp_ptr = arp1394->sip; /* move sender IP addr */
- arp_ptr += arp->ar_pln; /* skip over sender IP addr */
-
- if (arp->ar_op == htons(ARPOP_REQUEST))
- memset(arp_ptr, 0, sizeof(u64));
- else
- memcpy(arp_ptr, dev->dev_addr, sizeof(u64));
- }
-
- /* Now add the ethernet header. */
- if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
- skb->len) >= 0)
- ret = ether1394_type_trans(skb, dev);
-
- return ret;
-}
-
-static int fragment_overlap(struct list_head *frag_list, int offset, int len)
-{
- struct fragment_info *fi;
- int end = offset + len;
-
- list_for_each_entry(fi, frag_list, list)
- if (offset < fi->offset + fi->len && end > fi->offset)
- return 1;
-
- return 0;
-}
-
-static struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
-{
- struct partial_datagram *pd;
-
- list_for_each_entry(pd, pdgl, list)
- if (pd->dgl == dgl)
- return &pd->list;
-
- return NULL;
-}
-
-/* Assumes that new fragment does not overlap any existing fragments */
-static int new_fragment(struct list_head *frag_info, int offset, int len)
-{
- struct list_head *lh;
- struct fragment_info *fi, *fi2, *new;
-
- list_for_each(lh, frag_info) {
- fi = list_entry(lh, struct fragment_info, list);
- if (fi->offset + fi->len == offset) {
- /* The new fragment can be tacked on to the end */
- fi->len += len;
- /* Did the new fragment plug a hole? */
- fi2 = list_entry(lh->next, struct fragment_info, list);
- if (fi->offset + fi->len == fi2->offset) {
- /* glue fragments together */
- fi->len += fi2->len;
- list_del(lh->next);
- kfree(fi2);
- }
- return 0;
- } else if (offset + len == fi->offset) {
- /* The new fragment can be tacked on to the beginning */
- fi->offset = offset;
- fi->len += len;
- /* Did the new fragment plug a hole? */
- fi2 = list_entry(lh->prev, struct fragment_info, list);
- if (fi2->offset + fi2->len == fi->offset) {
- /* glue fragments together */
- fi2->len += fi->len;
- list_del(lh);
- kfree(fi);
- }
- return 0;
- } else if (offset > fi->offset + fi->len) {
- break;
- } else if (offset + len < fi->offset) {
- lh = lh->prev;
- break;
- }
- }
-
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
- if (!new)
- return -ENOMEM;
-
- new->offset = offset;
- new->len = len;
-
- list_add(&new->list, lh);
- return 0;
-}
-
-static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl,
- int dgl, int dg_size, char *frag_buf,
- int frag_off, int frag_len)
-{
- struct partial_datagram *new;
-
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
- if (!new)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&new->frag_info);
-
- if (new_fragment(&new->frag_info, frag_off, frag_len) < 0) {
- kfree(new);
- return -ENOMEM;
- }
-
- new->dgl = dgl;
- new->dg_size = dg_size;
-
- new->skb = dev_alloc_skb(dg_size + dev->hard_header_len + 15);
- if (!new->skb) {
- struct fragment_info *fi = list_entry(new->frag_info.next,
- struct fragment_info,
- list);
- kfree(fi);
- kfree(new);
- return -ENOMEM;
- }
-
- skb_reserve(new->skb, (dev->hard_header_len + 15) & ~15);
- new->pbuf = skb_put(new->skb, dg_size);
- memcpy(new->pbuf + frag_off, frag_buf, frag_len);
-
- list_add(&new->list, pdgl);
- return 0;
-}
-
-static int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
- char *frag_buf, int frag_off, int frag_len)
-{
- struct partial_datagram *pd =
- list_entry(lh, struct partial_datagram, list);
-
- if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0)
- return -ENOMEM;
-
- memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
-
- /* Move list entry to beginnig of list so that oldest partial
- * datagrams percolate to the end of the list */
- list_move(lh, pdgl);
- return 0;
-}
-
-static int is_datagram_complete(struct list_head *lh, int dg_size)
-{
- struct partial_datagram *pd;
- struct fragment_info *fi;
-
- pd = list_entry(lh, struct partial_datagram, list);
- fi = list_entry(pd->frag_info.next, struct fragment_info, list);
-
- return (fi->len == dg_size);
-}
-
-/* Packet reception. We convert the IP1394 encapsulation header to an
- * ethernet header, and fill it with some of our other fields. This is
- * an incoming packet from the 1394 bus. */
-static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
- char *buf, int len)
-{
- struct sk_buff *skb;
- unsigned long flags;
- struct eth1394_priv *priv = netdev_priv(dev);
- union eth1394_hdr *hdr = (union eth1394_hdr *)buf;
- __be16 ether_type = cpu_to_be16(0); /* initialized to clear warning */
- int hdr_len;
- struct unit_directory *ud = priv->ud_list[NODEID_TO_NODE(srcid)];
- struct eth1394_node_info *node_info;
-
- if (!ud) {
- struct eth1394_node_ref *node;
- node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid);
- if (unlikely(!node)) {
- HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid "
- "lookup failure: " NODE_BUS_FMT,
- NODE_BUS_ARGS(priv->host, srcid));
- dev->stats.rx_dropped++;
- return -1;
- }
- ud = node->ud;
-
- priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
- }
-
- node_info = dev_get_drvdata(&ud->device);
-
- /* First, did we receive a fragmented or unfragmented datagram? */
- hdr->words.word1 = ntohs(hdr->words.word1);
-
- hdr_len = hdr_type_len[hdr->common.lf];
-
- if (hdr->common.lf == ETH1394_HDR_LF_UF) {
- /* An unfragmented datagram has been received by the ieee1394
- * bus. Build an skbuff around it so we can pass it to the
- * high level network layer. */
-
- skb = dev_alloc_skb(len + dev->hard_header_len + 15);
- if (unlikely(!skb)) {
- ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
- dev->stats.rx_dropped++;
- return -1;
- }
- skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
- memcpy(skb_put(skb, len - hdr_len), buf + hdr_len,
- len - hdr_len);
- ether_type = hdr->uf.ether_type;
- } else {
- /* A datagram fragment has been received, now the fun begins. */
-
- struct list_head *pdgl, *lh;
- struct partial_datagram *pd;
- int fg_off;
- int fg_len = len - hdr_len;
- int dg_size;
- int dgl;
- int retval;
- struct pdg_list *pdg = &(node_info->pdg);
-
- hdr->words.word3 = ntohs(hdr->words.word3);
- /* The 4th header word is reserved so no need to do ntohs() */
-
- if (hdr->common.lf == ETH1394_HDR_LF_FF) {
- ether_type = hdr->ff.ether_type;
- dgl = hdr->ff.dgl;
- dg_size = hdr->ff.dg_size + 1;
- fg_off = 0;
- } else {
- hdr->words.word2 = ntohs(hdr->words.word2);
- dgl = hdr->sf.dgl;
- dg_size = hdr->sf.dg_size + 1;
- fg_off = hdr->sf.fg_off;
- }
- spin_lock_irqsave(&pdg->lock, flags);
-
- pdgl = &(pdg->list);
- lh = find_partial_datagram(pdgl, dgl);
-
- if (lh == NULL) {
- while (pdg->sz >= max_partial_datagrams) {
- /* remove the oldest */
- purge_partial_datagram(pdgl->prev);
- pdg->sz--;
- }
-
- retval = new_partial_datagram(dev, pdgl, dgl, dg_size,
- buf + hdr_len, fg_off,
- fg_len);
- if (retval < 0) {
- spin_unlock_irqrestore(&pdg->lock, flags);
- goto bad_proto;
- }
- pdg->sz++;
- lh = find_partial_datagram(pdgl, dgl);
- } else {
- pd = list_entry(lh, struct partial_datagram, list);
-
- if (fragment_overlap(&pd->frag_info, fg_off, fg_len)) {
- /* Overlapping fragments, obliterate old
- * datagram and start new one. */
- purge_partial_datagram(lh);
- retval = new_partial_datagram(dev, pdgl, dgl,
- dg_size,
- buf + hdr_len,
- fg_off, fg_len);
- if (retval < 0) {
- pdg->sz--;
- spin_unlock_irqrestore(&pdg->lock, flags);
- goto bad_proto;
- }
- } else {
- retval = update_partial_datagram(pdgl, lh,
- buf + hdr_len,
- fg_off, fg_len);
- if (retval < 0) {
- /* Couldn't save off fragment anyway
- * so might as well obliterate the
- * datagram now. */
- purge_partial_datagram(lh);
- pdg->sz--;
- spin_unlock_irqrestore(&pdg->lock, flags);
- goto bad_proto;
- }
- } /* fragment overlap */
- } /* new datagram or add to existing one */
-
- pd = list_entry(lh, struct partial_datagram, list);
-
- if (hdr->common.lf == ETH1394_HDR_LF_FF)
- pd->ether_type = ether_type;
-
- if (is_datagram_complete(lh, dg_size)) {
- ether_type = pd->ether_type;
- pdg->sz--;
- skb = skb_get(pd->skb);
- purge_partial_datagram(lh);
- spin_unlock_irqrestore(&pdg->lock, flags);
- } else {
- /* Datagram is not complete, we're done for the
- * moment. */
- spin_unlock_irqrestore(&pdg->lock, flags);
- return 0;
- }
- } /* unframgented datagram or fragmented one */
-
- /* Write metadata, and then pass to the receive level */
- skb->dev = dev;
- skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
-
- /* Parse the encapsulation header. This actually does the job of
- * converting to an ethernet frame header, aswell as arp
- * conversion if needed. ARP conversion is easier in this
- * direction, since we are using ethernet as our backend. */
- skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid,
- ether_type);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (!skb->protocol) {
- dev->stats.rx_errors++;
- dev->stats.rx_dropped++;
- dev_kfree_skb_any(skb);
- } else if (netif_rx(skb) == NET_RX_DROP) {
- dev->stats.rx_errors++;
- dev->stats.rx_dropped++;
- } else {
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
-bad_proto:
- if (netif_queue_stopped(dev))
- netif_wake_queue(dev);
-
- return 0;
-}
-
-static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
- quadlet_t *data, u64 addr, size_t len, u16 flags)
-{
- struct eth1394_host_info *hi;
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
- if (unlikely(!hi)) {
- ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
- host->id);
- return RCODE_ADDRESS_ERROR;
- }
-
- if (ether1394_data_handler(hi->dev, srcid, destid, (char*)data, len))
- return RCODE_ADDRESS_ERROR;
- else
- return RCODE_COMPLETE;
-}
-
-static void ether1394_iso(struct hpsb_iso *iso)
-{
- __be32 *data;
- char *buf;
- struct eth1394_host_info *hi;
- struct net_device *dev;
- unsigned int len;
- u32 specifier_id;
- u16 source_id;
- int i;
- int nready;
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
- if (unlikely(!hi)) {
- ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
- iso->host->id);
- return;
- }
-
- dev = hi->dev;
-
- nready = hpsb_iso_n_ready(iso);
- for (i = 0; i < nready; i++) {
- struct hpsb_iso_packet_info *info =
- &iso->infos[(iso->first_packet + i) % iso->buf_packets];
- data = (__be32 *)(iso->data_buf.kvirt + info->offset);
-
- /* skip over GASP header */
- buf = (char *)data + 8;
- len = info->len - 8;
-
- specifier_id = (be32_to_cpu(data[0]) & 0xffff) << 8 |
- (be32_to_cpu(data[1]) & 0xff000000) >> 24;
- source_id = be32_to_cpu(data[0]) >> 16;
-
- if (info->channel != (iso->host->csr.broadcast_channel & 0x3f)
- || specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
- /* This packet is not for us */
- continue;
- }
- ether1394_data_handler(dev, source_id, LOCAL_BUS | ALL_NODES,
- buf, len);
- }
-
- hpsb_iso_recv_release_packets(iso, i);
-
-}
-
-/******************************************
- * Datagram transmission code
- ******************************************/
-
-/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the entire
- * arphdr) is the same format as the ip1394 header, so they overlap. The rest
- * needs to be munged a bit. The remainder of the arphdr is formatted based
- * on hwaddr len and ipaddr len. We know what they'll be, so it's easy to
- * judge.
- *
- * Now that the EUI is used for the hardware address all we need to do to make
- * this work for 1394 is to insert 2 quadlets that contain max_rec size,
- * speed, and unicast FIFO address information between the sender_unique_id
- * and the IP addresses.
- */
-static void ether1394_arp_to_1394arp(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct eth1394_priv *priv = netdev_priv(dev);
- struct arphdr *arp = (struct arphdr *)skb->data;
- unsigned char *arp_ptr = (unsigned char *)(arp + 1);
- struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
-
- arp1394->hw_addr_len = 16;
- arp1394->sip = *(u32*)(arp_ptr + ETH1394_ALEN);
- arp1394->max_rec = priv->host->csr.max_rec;
- arp1394->sspd = priv->host->csr.lnk_spd;
- arp1394->fifo_hi = htons(priv->local_fifo >> 32);
- arp1394->fifo_lo = htonl(priv->local_fifo & ~0x0);
-}
-
-/* We need to encapsulate the standard header with our own. We use the
- * ethernet header's proto for our own. */
-static unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
- __be16 proto,
- union eth1394_hdr *hdr,
- u16 dg_size, u16 dgl)
-{
- unsigned int adj_max_payload =
- max_payload - hdr_type_len[ETH1394_HDR_LF_UF];
-
- /* Does it all fit in one packet? */
- if (dg_size <= adj_max_payload) {
- hdr->uf.lf = ETH1394_HDR_LF_UF;
- hdr->uf.ether_type = proto;
- } else {
- hdr->ff.lf = ETH1394_HDR_LF_FF;
- hdr->ff.ether_type = proto;
- hdr->ff.dg_size = dg_size - 1;
- hdr->ff.dgl = dgl;
- adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF];
- }
- return DIV_ROUND_UP(dg_size, adj_max_payload);
-}
-
-static unsigned int ether1394_encapsulate(struct sk_buff *skb,
- unsigned int max_payload,
- union eth1394_hdr *hdr)
-{
- union eth1394_hdr *bufhdr;
- int ftype = hdr->common.lf;
- int hdrsz = hdr_type_len[ftype];
- unsigned int adj_max_payload = max_payload - hdrsz;
-
- switch (ftype) {
- case ETH1394_HDR_LF_UF:
- bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
- bufhdr->words.word1 = htons(hdr->words.word1);
- bufhdr->words.word2 = hdr->words.word2;
- break;
-
- case ETH1394_HDR_LF_FF:
- bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
- bufhdr->words.word1 = htons(hdr->words.word1);
- bufhdr->words.word2 = hdr->words.word2;
- bufhdr->words.word3 = htons(hdr->words.word3);
- bufhdr->words.word4 = 0;
-
- /* Set frag type here for future interior fragments */
- hdr->common.lf = ETH1394_HDR_LF_IF;
- hdr->sf.fg_off = 0;
- break;
-
- default:
- hdr->sf.fg_off += adj_max_payload;
- bufhdr = (union eth1394_hdr *)skb_pull(skb, adj_max_payload);
- if (max_payload >= skb->len)
- hdr->common.lf = ETH1394_HDR_LF_LF;
- bufhdr->words.word1 = htons(hdr->words.word1);
- bufhdr->words.word2 = htons(hdr->words.word2);
- bufhdr->words.word3 = htons(hdr->words.word3);
- bufhdr->words.word4 = 0;
- }
- return min(max_payload, skb->len);
-}
-
-static struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host)
-{
- struct hpsb_packet *p;
-
- p = hpsb_alloc_packet(0);
- if (p) {
- p->host = host;
- p->generation = get_hpsb_generation(host);
- p->type = hpsb_async;
- }
- return p;
-}
-
-static int ether1394_prep_write_packet(struct hpsb_packet *p,
- struct hpsb_host *host, nodeid_t node,
- u64 addr, void *data, int tx_len)
-{
- p->node_id = node;
-
- if (hpsb_get_tlabel(p))
- return -EAGAIN;
-
- p->tcode = TCODE_WRITEB;
- p->header_size = 16;
- p->expect_response = 1;
- p->header[0] =
- p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4;
- p->header[1] = host->node_id << 16 | addr >> 32;
- p->header[2] = addr & 0xffffffff;
- p->header[3] = tx_len << 16;
- p->data_size = (tx_len + 3) & ~3;
- p->data = data;
-
- return 0;
-}
-
-static void ether1394_prep_gasp_packet(struct hpsb_packet *p,
- struct eth1394_priv *priv,
- struct sk_buff *skb, int length)
-{
- p->header_size = 4;
- p->tcode = TCODE_STREAM_DATA;
-
- p->header[0] = length << 16 | 3 << 14 | priv->broadcast_channel << 8 |
- TCODE_STREAM_DATA << 4;
- p->data_size = length;
- p->data = (quadlet_t *)skb->data - 2;
- p->data[0] = cpu_to_be32(priv->host->node_id << 16 |
- ETHER1394_GASP_SPECIFIER_ID_HI);
- p->data[1] = cpu_to_be32(ETHER1394_GASP_SPECIFIER_ID_LO << 24 |
- ETHER1394_GASP_VERSION);
-
- p->speed_code = priv->bc_sspd;
-
- /* prevent hpsb_send_packet() from overriding our speed code */
- p->node_id = LOCAL_BUS | ALL_NODES;
-}
-
-static void ether1394_free_packet(struct hpsb_packet *packet)
-{
- if (packet->tcode != TCODE_STREAM_DATA)
- hpsb_free_tlabel(packet);
- hpsb_free_packet(packet);
-}
-
-static void ether1394_complete_cb(void *__ptask);
-
-static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
-{
- struct eth1394_priv *priv = ptask->priv;
- struct hpsb_packet *packet = NULL;
-
- packet = ether1394_alloc_common_packet(priv->host);
- if (!packet)
- return -ENOMEM;
-
- if (ptask->tx_type == ETH1394_GASP) {
- int length = tx_len + 2 * sizeof(quadlet_t);
-
- ether1394_prep_gasp_packet(packet, priv, ptask->skb, length);
- } else if (ether1394_prep_write_packet(packet, priv->host,
- ptask->dest_node,
- ptask->addr, ptask->skb->data,
- tx_len)) {
- hpsb_free_packet(packet);
- return -EAGAIN;
- }
-
- ptask->packet = packet;
- hpsb_set_packet_complete_task(ptask->packet, ether1394_complete_cb,
- ptask);
-
- if (hpsb_send_packet(packet) < 0) {
- ether1394_free_packet(packet);
- return -EIO;
- }
-
- return 0;
-}
-
-/* Task function to be run when a datagram transmission is completed */
-static void ether1394_dg_complete(struct packet_task *ptask, int fail)
-{
- struct sk_buff *skb = ptask->skb;
- struct net_device *dev = skb->dev;
- struct eth1394_priv *priv = netdev_priv(dev);
- unsigned long flags;
-
- /* Statistics */
- spin_lock_irqsave(&priv->lock, flags);
- if (fail) {
- dev->stats.tx_dropped++;
- dev->stats.tx_errors++;
- } else {
- dev->stats.tx_bytes += skb->len;
- dev->stats.tx_packets++;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- dev_kfree_skb_any(skb);
- kmem_cache_free(packet_task_cache, ptask);
-}
-
-/* Callback for when a packet has been sent and the status of that packet is
- * known */
-static void ether1394_complete_cb(void *__ptask)
-{
- struct packet_task *ptask = (struct packet_task *)__ptask;
- struct hpsb_packet *packet = ptask->packet;
- int fail = 0;
-
- if (packet->tcode != TCODE_STREAM_DATA)
- fail = hpsb_packet_success(packet);
-
- ether1394_free_packet(packet);
-
- ptask->outstanding_pkts--;
- if (ptask->outstanding_pkts > 0 && !fail) {
- int tx_len, err;
-
- /* Add the encapsulation header to the fragment */
- tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload,
- &ptask->hdr);
- err = ether1394_send_packet(ptask, tx_len);
- if (err) {
- if (err == -EAGAIN)
- ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n");
-
- ether1394_dg_complete(ptask, 1);
- }
- } else {
- ether1394_dg_complete(ptask, fail);
- }
-}
-
-/* Transmit a packet (called by kernel) */
-static netdev_tx_t ether1394_tx(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct eth1394hdr hdr_buf;
- struct eth1394_priv *priv = netdev_priv(dev);
- __be16 proto;
- unsigned long flags;
- nodeid_t dest_node;
- eth1394_tx_type tx_type;
- unsigned int tx_len;
- unsigned int max_payload;
- u16 dg_size;
- u16 dgl;
- struct packet_task *ptask;
- struct eth1394_node_ref *node;
- struct eth1394_node_info *node_info = NULL;
-
- ptask = kmem_cache_alloc(packet_task_cache, GFP_ATOMIC);
- if (ptask == NULL)
- goto fail;
-
- /* XXX Ignore this for now. Noticed that when MacOSX is the IRM,
- * it does not set our validity bit. We need to compensate for
- * that somewhere else, but not in eth1394. */
-#if 0
- if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000)
- goto fail;
-#endif
-
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (!skb)
- goto fail;
-
- /* Get rid of the fake eth1394 header, but first make a copy.
- * We might need to rebuild the header on tx failure. */
- memcpy(&hdr_buf, skb->data, sizeof(hdr_buf));
- skb_pull(skb, ETH1394_HLEN);
-
- proto = hdr_buf.h_proto;
- dg_size = skb->len;
-
- /* Set the transmission type for the packet. ARP packets and IP
- * broadcast packets are sent via GASP. */
- if (memcmp(hdr_buf.h_dest, dev->broadcast, ETH1394_ALEN) == 0 ||
- proto == htons(ETH_P_ARP) ||
- (proto == htons(ETH_P_IP) &&
- IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) {
- tx_type = ETH1394_GASP;
- dest_node = LOCAL_BUS | ALL_NODES;
- max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD;
- BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
- dgl = priv->bc_dgl;
- if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
- priv->bc_dgl++;
- } else {
- __be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest);
-
- node = eth1394_find_node_guid(&priv->ip_node_list,
- be64_to_cpu(guid));
- if (!node)
- goto fail;
-
- node_info = dev_get_drvdata(&node->ud->device);
- if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE)
- goto fail;
-
- dest_node = node->ud->ne->nodeid;
- max_payload = node_info->maxpayload;
- BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
-
- dgl = node_info->dgl;
- if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
- node_info->dgl++;
- tx_type = ETH1394_WRREQ;
- }
-
- /* If this is an ARP packet, convert it */
- if (proto == htons(ETH_P_ARP))
- ether1394_arp_to_1394arp(skb, dev);
-
- ptask->hdr.words.word1 = 0;
- ptask->hdr.words.word2 = 0;
- ptask->hdr.words.word3 = 0;
- ptask->hdr.words.word4 = 0;
- ptask->skb = skb;
- ptask->priv = priv;
- ptask->tx_type = tx_type;
-
- if (tx_type != ETH1394_GASP) {
- u64 addr;
-
- spin_lock_irqsave(&priv->lock, flags);
- addr = node_info->fifo;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- ptask->addr = addr;
- ptask->dest_node = dest_node;
- }
-
- ptask->tx_type = tx_type;
- ptask->max_payload = max_payload;
- ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload,
- proto, &ptask->hdr, dg_size, dgl);
-
- /* Add the encapsulation header to the fragment */
- tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr);
- dev->trans_start = jiffies;
- if (ether1394_send_packet(ptask, tx_len)) {
- if (dest_node == (LOCAL_BUS | ALL_NODES))
- goto fail;
-
- /* At this point we want to restore the packet. When we return
- * here with NETDEV_TX_BUSY we will get another entrance in this
- * routine with the same skb and we need it to look the same.
- * So we pull 4 more bytes, then build the header again. */
- skb_pull(skb, 4);
- ether1394_header(skb, dev, ntohs(hdr_buf.h_proto),
- hdr_buf.h_dest, NULL, 0);
-
- /* Most failures of ether1394_send_packet are recoverable. */
- netif_stop_queue(dev);
- priv->wake_node = dest_node;
- schedule_work(&priv->wake);
- kmem_cache_free(packet_task_cache, ptask);
- return NETDEV_TX_BUSY;
- }
-
- return NETDEV_TX_OK;
-fail:
- if (ptask)
- kmem_cache_free(packet_task_cache, ptask);
-
- if (skb != NULL)
- dev_kfree_skb(skb);
-
- spin_lock_irqsave(&priv->lock, flags);
- dev->stats.tx_dropped++;
- dev->stats.tx_errors++;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return NETDEV_TX_OK;
-}
-
-static int __init ether1394_init_module(void)
-{
- int err;
-
- packet_task_cache = kmem_cache_create("packet_task",
- sizeof(struct packet_task),
- 0, 0, NULL);
- if (!packet_task_cache)
- return -ENOMEM;
-
- hpsb_register_highlevel(&eth1394_highlevel);
- err = hpsb_register_protocol(&eth1394_proto_driver);
- if (err) {
- hpsb_unregister_highlevel(&eth1394_highlevel);
- kmem_cache_destroy(packet_task_cache);
- }
- return err;
-}
-
-static void __exit ether1394_exit_module(void)
-{
- hpsb_unregister_protocol(&eth1394_proto_driver);
- hpsb_unregister_highlevel(&eth1394_highlevel);
- kmem_cache_destroy(packet_task_cache);
-}
-
-module_init(ether1394_init_module);
-module_exit(ether1394_exit_module);
diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h
deleted file mode 100644
index d53bac47b86f..000000000000
--- a/drivers/ieee1394/eth1394.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem
- *
- * Copyright (C) 2000 Bonin Franck <boninf@free.fr>
- * (C) 2001 Ben Collins <bcollins@debian.org>
- *
- * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
- *
- * 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.
- */
-
-#ifndef __ETH1394_H
-#define __ETH1394_H
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <asm/byteorder.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-
-/* Register for incoming packets. This is 4096 bytes, which supports up to
- * S3200 (per Table 16-3 of IEEE 1394b-2002). */
-#define ETHER1394_REGION_ADDR_LEN 4096
-
-/* GASP identifier numbers for IPv4 over IEEE 1394 */
-#define ETHER1394_GASP_SPECIFIER_ID 0x00005E
-#define ETHER1394_GASP_SPECIFIER_ID_HI ((0x00005E >> 8) & 0xffff)
-#define ETHER1394_GASP_SPECIFIER_ID_LO (0x00005E & 0xff)
-#define ETHER1394_GASP_VERSION 1
-
-#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* for GASP header */
-
-#define ETHER1394_GASP_BUFFERS 16
-
-#define NODE_SET (ALL_NODES + 1) /* Node set == 64 */
-
-enum eth1394_bc_states { ETHER1394_BC_ERROR,
- ETHER1394_BC_RUNNING,
- ETHER1394_BC_STOPPED };
-
-
-/* Private structure for our ethernet driver */
-struct eth1394_priv {
- struct hpsb_host *host; /* The card for this dev */
- u16 bc_maxpayload; /* Max broadcast payload */
- u8 bc_sspd; /* Max broadcast speed */
- u64 local_fifo; /* Local FIFO Address */
- spinlock_t lock; /* Private lock */
- int broadcast_channel; /* Async stream Broadcast Channel */
- enum eth1394_bc_states bc_state; /* broadcast channel state */
- struct hpsb_iso *iso; /* Async stream recv handle */
- int bc_dgl; /* Outgoing broadcast datagram label */
- struct list_head ip_node_list; /* List of IP capable nodes */
- struct unit_directory *ud_list[ALL_NODES]; /* Cached unit dir list */
-
- struct work_struct wake; /* Wake up after xmit failure */
- struct net_device *wake_dev; /* Stupid backlink for .wake */
- nodeid_t wake_node; /* Destination of failed xmit */
-};
-
-
-/* Define a fake hardware header format for the networking core. Note that
- * header size cannot exceed 16 bytes as that is the size of the header cache.
- * Also, we do not need the source address in the header so we omit it and
- * keep the header to under 16 bytes */
-#define ETH1394_ALEN (8)
-#define ETH1394_HLEN (10)
-
-struct eth1394hdr {
- unsigned char h_dest[ETH1394_ALEN]; /* destination eth1394 addr */
- __be16 h_proto; /* packet type ID field */
-} __attribute__((packed));
-
-static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb)
-{
- return (struct eth1394hdr *)skb_mac_header(skb);
-}
-
-typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
-
-/* IP1394 headers */
-
-/* Unfragmented */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_uf_hdr {
- u16 lf:2;
- u16 res:14;
- __be16 ether_type; /* Ethernet packet type */
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_uf_hdr {
- u16 res:14;
- u16 lf:2;
- __be16 ether_type;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-/* First fragment */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_ff_hdr {
- u16 lf:2;
- u16 res1:2;
- u16 dg_size:12; /* Datagram size */
- __be16 ether_type; /* Ethernet packet type */
- u16 dgl; /* Datagram label */
- u16 res2;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_ff_hdr {
- u16 dg_size:12;
- u16 res1:2;
- u16 lf:2;
- __be16 ether_type;
- u16 dgl;
- u16 res2;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-/* XXX: Subsequent fragments, including last */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_sf_hdr {
- u16 lf:2;
- u16 res1:2;
- u16 dg_size:12; /* Datagram size */
- u16 res2:4;
- u16 fg_off:12; /* Fragment offset */
- u16 dgl; /* Datagram label */
- u16 res3;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_sf_hdr {
- u16 dg_size:12;
- u16 res1:2;
- u16 lf:2;
- u16 fg_off:12;
- u16 res2:4;
- u16 dgl;
- u16 res3;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_common_hdr {
- u16 lf:2;
- u16 pad1:14;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_common_hdr {
- u16 pad1:14;
- u16 lf:2;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-struct eth1394_hdr_words {
- u16 word1;
- u16 word2;
- u16 word3;
- u16 word4;
-};
-
-union eth1394_hdr {
- struct eth1394_common_hdr common;
- struct eth1394_uf_hdr uf;
- struct eth1394_ff_hdr ff;
- struct eth1394_sf_hdr sf;
- struct eth1394_hdr_words words;
-};
-
-/* End of IP1394 headers */
-
-/* Fragment types */
-#define ETH1394_HDR_LF_UF 0 /* unfragmented */
-#define ETH1394_HDR_LF_FF 1 /* first fragment */
-#define ETH1394_HDR_LF_LF 2 /* last fragment */
-#define ETH1394_HDR_LF_IF 3 /* interior fragment */
-
-#define IP1394_HW_ADDR_LEN 16 /* As per RFC */
-
-/* Our arp packet (ARPHRD_IEEE1394) */
-struct eth1394_arp {
- u16 hw_type; /* 0x0018 */
- u16 proto_type; /* 0x0806 */
- u8 hw_addr_len; /* 16 */
- u8 ip_addr_len; /* 4 */
- u16 opcode; /* ARP Opcode */
- /* Above is exactly the same format as struct arphdr */
-
- __be64 s_uniq_id; /* Sender's 64bit EUI */
- u8 max_rec; /* Sender's max packet size */
- u8 sspd; /* Sender's max speed */
- __be16 fifo_hi; /* hi 16bits of sender's FIFO addr */
- __be32 fifo_lo; /* lo 32bits of sender's FIFO addr */
- u32 sip; /* Sender's IP Address */
- u32 tip; /* IP Address of requested hw addr */
-};
-
-/* Network timeout */
-#define ETHER1394_TIMEOUT 100000
-
-/* This is our task struct. It's used for the packet complete callback. */
-struct packet_task {
- struct sk_buff *skb;
- int outstanding_pkts;
- eth1394_tx_type tx_type;
- int max_payload;
- struct hpsb_packet *packet;
- struct eth1394_priv *priv;
- union eth1394_hdr hdr;
- u64 addr;
- u16 dest_node;
-};
-
-#endif /* __ETH1394_H */
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
deleted file mode 100644
index 4bc443546e04..000000000000
--- a/drivers/ieee1394/highlevel.c
+++ /dev/null
@@ -1,691 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Christian Toegel <christian.toegel@gmx.at>
- * unregister address space
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * unregister address space
- *
- */
-
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "nodemgr.h"
-
-
-struct hl_host_info {
- struct list_head list;
- struct hpsb_host *host;
- size_t size;
- unsigned long key;
- void *data;
-};
-
-
-static LIST_HEAD(hl_drivers);
-static DECLARE_RWSEM(hl_drivers_sem);
-
-static LIST_HEAD(hl_irqs);
-static DEFINE_RWLOCK(hl_irqs_lock);
-
-static DEFINE_RWLOCK(addr_space_lock);
-
-
-static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
- struct hpsb_host *host)
-{
- struct hl_host_info *hi = NULL;
-
- if (!hl || !host)
- return NULL;
-
- read_lock(&hl->host_info_lock);
- list_for_each_entry(hi, &hl->host_info_list, list) {
- if (hi->host == host) {
- read_unlock(&hl->host_info_lock);
- return hi;
- }
- }
- read_unlock(&hl->host_info_lock);
- return NULL;
-}
-
-/**
- * hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
- *
- * Returns a per @host and @hl driver data structure that was previously stored
- * by hpsb_create_hostinfo.
- */
-void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
-{
- struct hl_host_info *hi = hl_get_hostinfo(hl, host);
-
- return hi ? hi->data : NULL;
-}
-
-/**
- * hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
- *
- * Allocate a hostinfo pointer backed by memory with @data_size and bind it to
- * to this @hl driver and @host. If @data_size is zero, then the return here is
- * only valid for error checking.
- */
-void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
- size_t data_size)
-{
- struct hl_host_info *hi;
- void *data;
- unsigned long flags;
-
- hi = hl_get_hostinfo(hl, host);
- if (hi) {
- HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already"
- " exists", hl->name);
- return NULL;
- }
-
- hi = kzalloc(sizeof(*hi) + data_size, GFP_ATOMIC);
- if (!hi)
- return NULL;
-
- if (data_size) {
- data = hi->data = hi + 1;
- hi->size = data_size;
- } else
- data = hi;
-
- hi->host = host;
-
- write_lock_irqsave(&hl->host_info_lock, flags);
- list_add_tail(&hi->list, &hl->host_info_list);
- write_unlock_irqrestore(&hl->host_info_lock, flags);
-
- return data;
-}
-
-/**
- * hpsb_set_hostinfo - set the hostinfo pointer to something useful
- *
- * Usually follows a call to hpsb_create_hostinfo, where the size is 0.
- */
-int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
- void *data)
-{
- struct hl_host_info *hi;
-
- hi = hl_get_hostinfo(hl, host);
- if (hi) {
- if (!hi->size && !hi->data) {
- hi->data = data;
- return 0;
- } else
- HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo "
- "already has data", hl->name);
- } else
- HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
- hl->name);
- return -EINVAL;
-}
-
-/**
- * hpsb_destroy_hostinfo - free and remove a hostinfo pointer
- *
- * Free and remove the hostinfo pointer bound to this @hl driver and @host.
- */
-void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
-{
- struct hl_host_info *hi;
-
- hi = hl_get_hostinfo(hl, host);
- if (hi) {
- unsigned long flags;
- write_lock_irqsave(&hl->host_info_lock, flags);
- list_del(&hi->list);
- write_unlock_irqrestore(&hl->host_info_lock, flags);
- kfree(hi);
- }
- return;
-}
-
-/**
- * hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
- *
- * Sets an alternate lookup key for the hostinfo bound to this @hl driver and
- * @host.
- */
-void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
- unsigned long key)
-{
- struct hl_host_info *hi;
-
- hi = hl_get_hostinfo(hl, host);
- if (hi)
- hi->key = key;
- return;
-}
-
-/**
- * hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
- */
-void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
-{
- struct hl_host_info *hi;
- void *data = NULL;
-
- if (!hl)
- return NULL;
-
- read_lock(&hl->host_info_lock);
- list_for_each_entry(hi, &hl->host_info_list, list) {
- if (hi->key == key) {
- data = hi->data;
- break;
- }
- }
- read_unlock(&hl->host_info_lock);
- return data;
-}
-
-static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
-{
- struct hpsb_highlevel *hl = __data;
-
- hl->add_host(host);
-
- if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
- HPSB_ERR("Failed to generate Configuration ROM image for host "
- "%s-%d", hl->name, host->id);
- return 0;
-}
-
-/**
- * hpsb_register_highlevel - register highlevel driver
- *
- * The name pointer in @hl has to stay valid at all times because the string is
- * not copied.
- */
-void hpsb_register_highlevel(struct hpsb_highlevel *hl)
-{
- unsigned long flags;
-
- hpsb_init_highlevel(hl);
- INIT_LIST_HEAD(&hl->addr_list);
-
- down_write(&hl_drivers_sem);
- list_add_tail(&hl->hl_list, &hl_drivers);
- up_write(&hl_drivers_sem);
-
- write_lock_irqsave(&hl_irqs_lock, flags);
- list_add_tail(&hl->irq_list, &hl_irqs);
- write_unlock_irqrestore(&hl_irqs_lock, flags);
-
- if (hl->add_host)
- nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
- return;
-}
-
-static void __delete_addr(struct hpsb_address_serve *as)
-{
- list_del(&as->host_list);
- list_del(&as->hl_list);
- kfree(as);
-}
-
-static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
- int update_cr)
-{
- unsigned long flags;
- struct list_head *lh, *next;
- struct hpsb_address_serve *as;
-
- /* First, let the highlevel driver unreg */
- if (hl->remove_host)
- hl->remove_host(host);
-
- /* Remove any addresses that are matched for this highlevel driver
- * and this particular host. */
- write_lock_irqsave(&addr_space_lock, flags);
- list_for_each_safe (lh, next, &hl->addr_list) {
- as = list_entry(lh, struct hpsb_address_serve, hl_list);
- if (as->host == host)
- __delete_addr(as);
- }
- write_unlock_irqrestore(&addr_space_lock, flags);
-
- /* Now update the config-rom to reflect anything removed by the
- * highlevel driver. */
- if (update_cr && host->update_config_rom &&
- hpsb_update_config_rom_image(host) < 0)
- HPSB_ERR("Failed to generate Configuration ROM image for host "
- "%s-%d", hl->name, host->id);
-
- /* Finally remove all the host info associated between these two. */
- hpsb_destroy_hostinfo(hl, host);
-}
-
-static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
-{
- struct hpsb_highlevel *hl = __data;
-
- __unregister_host(hl, host, 1);
- return 0;
-}
-
-/**
- * hpsb_unregister_highlevel - unregister highlevel driver
- */
-void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
-{
- unsigned long flags;
-
- write_lock_irqsave(&hl_irqs_lock, flags);
- list_del(&hl->irq_list);
- write_unlock_irqrestore(&hl_irqs_lock, flags);
-
- down_write(&hl_drivers_sem);
- list_del(&hl->hl_list);
- up_write(&hl_drivers_sem);
-
- nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
-}
-
-/**
- * hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
- *
- * @start and @end are 48 bit pointers and have to be quadlet aligned.
- * @end points to the first address behind the handled addresses. This
- * function can be called multiple times for a single hpsb_highlevel @hl to
- * implement sparse register sets. The requested region must not overlap any
- * previously allocated region, otherwise registering will fail.
- *
- * It returns true for successful allocation. Address spaces can be
- * unregistered with hpsb_unregister_addrspace. All remaining address spaces
- * are automatically deallocated together with the hpsb_highlevel @hl.
- */
-u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
- struct hpsb_host *host,
- const struct hpsb_address_ops *ops,
- u64 size, u64 alignment,
- u64 start, u64 end)
-{
- struct hpsb_address_serve *as, *a1, *a2;
- struct list_head *entry;
- u64 retval = CSR1212_INVALID_ADDR_SPACE;
- unsigned long flags;
- u64 align_mask = ~(alignment - 1);
-
- if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
- (hweight64(alignment) != 1)) {
- HPSB_ERR("%s called with invalid alignment: 0x%048llx",
- __func__, (unsigned long long)alignment);
- return retval;
- }
-
- /* default range,
- * avoids controller's posted write area (see OHCI 1.1 clause 1.5) */
- if (start == CSR1212_INVALID_ADDR_SPACE &&
- end == CSR1212_INVALID_ADDR_SPACE) {
- start = host->middle_addr_space;
- end = CSR1212_ALL_SPACE_END;
- }
-
- if (((start|end) & ~align_mask) || (start >= end) ||
- (end > CSR1212_ALL_SPACE_END)) {
- HPSB_ERR("%s called with invalid addresses "
- "(start = %012Lx end = %012Lx)", __func__,
- (unsigned long long)start,(unsigned long long)end);
- return retval;
- }
-
- as = kmalloc(sizeof(*as), GFP_KERNEL);
- if (!as)
- return retval;
-
- INIT_LIST_HEAD(&as->host_list);
- INIT_LIST_HEAD(&as->hl_list);
- as->op = ops;
- as->host = host;
-
- write_lock_irqsave(&addr_space_lock, flags);
- list_for_each(entry, &host->addr_space) {
- u64 a1sa, a1ea;
- u64 a2sa, a2ea;
-
- a1 = list_entry(entry, struct hpsb_address_serve, host_list);
- a2 = list_entry(entry->next, struct hpsb_address_serve,
- host_list);
-
- a1sa = a1->start & align_mask;
- a1ea = (a1->end + alignment -1) & align_mask;
- a2sa = a2->start & align_mask;
- a2ea = (a2->end + alignment -1) & align_mask;
-
- if ((a2sa - a1ea >= size) && (a2sa - start >= size) &&
- (a2sa > start)) {
- as->start = max(start, a1ea);
- as->end = as->start + size;
- list_add(&as->host_list, entry);
- list_add_tail(&as->hl_list, &hl->addr_list);
- retval = as->start;
- break;
- }
- }
- write_unlock_irqrestore(&addr_space_lock, flags);
-
- if (retval == CSR1212_INVALID_ADDR_SPACE)
- kfree(as);
- return retval;
-}
-
-/**
- * hpsb_register_addrspace - register a host address space
- *
- * @start and @end are 48 bit pointers and have to be quadlet aligned.
- * @end points to the first address behind the handled addresses. This
- * function can be called multiple times for a single hpsb_highlevel @hl to
- * implement sparse register sets. The requested region must not overlap any
- * previously allocated region, otherwise registering will fail.
- *
- * It returns true for successful allocation. Address spaces can be
- * unregistered with hpsb_unregister_addrspace. All remaining address spaces
- * are automatically deallocated together with the hpsb_highlevel @hl.
- */
-int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- const struct hpsb_address_ops *ops,
- u64 start, u64 end)
-{
- struct hpsb_address_serve *as;
- struct list_head *lh;
- int retval = 0;
- unsigned long flags;
-
- if (((start|end) & 3) || (start >= end) ||
- (end > CSR1212_ALL_SPACE_END)) {
- HPSB_ERR("%s called with invalid addresses", __func__);
- return 0;
- }
-
- as = kmalloc(sizeof(*as), GFP_KERNEL);
- if (!as)
- return 0;
-
- INIT_LIST_HEAD(&as->host_list);
- INIT_LIST_HEAD(&as->hl_list);
- as->op = ops;
- as->start = start;
- as->end = end;
- as->host = host;
-
- write_lock_irqsave(&addr_space_lock, flags);
- list_for_each(lh, &host->addr_space) {
- struct hpsb_address_serve *as_this =
- list_entry(lh, struct hpsb_address_serve, host_list);
- struct hpsb_address_serve *as_next =
- list_entry(lh->next, struct hpsb_address_serve,
- host_list);
-
- if (as_this->end > as->start)
- break;
-
- if (as_next->start >= as->end) {
- list_add(&as->host_list, lh);
- list_add_tail(&as->hl_list, &hl->addr_list);
- retval = 1;
- break;
- }
- }
- write_unlock_irqrestore(&addr_space_lock, flags);
-
- if (retval == 0)
- kfree(as);
- return retval;
-}
-
-int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- u64 start)
-{
- int retval = 0;
- struct hpsb_address_serve *as;
- struct list_head *lh, *next;
- unsigned long flags;
-
- write_lock_irqsave(&addr_space_lock, flags);
- list_for_each_safe (lh, next, &hl->addr_list) {
- as = list_entry(lh, struct hpsb_address_serve, hl_list);
- if (as->start == start && as->host == host) {
- __delete_addr(as);
- retval = 1;
- break;
- }
- }
- write_unlock_irqrestore(&addr_space_lock, flags);
- return retval;
-}
-
-static const struct hpsb_address_ops dummy_ops;
-
-/* dummy address spaces as lower and upper bounds of the host's a.s. list */
-static void init_hpsb_highlevel(struct hpsb_host *host)
-{
- INIT_LIST_HEAD(&host->dummy_zero_addr.host_list);
- INIT_LIST_HEAD(&host->dummy_zero_addr.hl_list);
- INIT_LIST_HEAD(&host->dummy_max_addr.host_list);
- INIT_LIST_HEAD(&host->dummy_max_addr.hl_list);
-
- host->dummy_zero_addr.op = host->dummy_max_addr.op = &dummy_ops;
-
- host->dummy_zero_addr.start = host->dummy_zero_addr.end = 0;
- host->dummy_max_addr.start = host->dummy_max_addr.end = ((u64) 1) << 48;
-
- list_add_tail(&host->dummy_zero_addr.host_list, &host->addr_space);
- list_add_tail(&host->dummy_max_addr.host_list, &host->addr_space);
-}
-
-void highlevel_add_host(struct hpsb_host *host)
-{
- struct hpsb_highlevel *hl;
-
- init_hpsb_highlevel(host);
-
- down_read(&hl_drivers_sem);
- list_for_each_entry(hl, &hl_drivers, hl_list) {
- if (hl->add_host)
- hl->add_host(host);
- }
- up_read(&hl_drivers_sem);
- if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
- HPSB_ERR("Failed to generate Configuration ROM image for host "
- "%s-%d", hl->name, host->id);
-}
-
-void highlevel_remove_host(struct hpsb_host *host)
-{
- struct hpsb_highlevel *hl;
-
- down_read(&hl_drivers_sem);
- list_for_each_entry(hl, &hl_drivers, hl_list)
- __unregister_host(hl, host, 0);
- up_read(&hl_drivers_sem);
-}
-
-void highlevel_host_reset(struct hpsb_host *host)
-{
- unsigned long flags;
- struct hpsb_highlevel *hl;
-
- read_lock_irqsave(&hl_irqs_lock, flags);
- list_for_each_entry(hl, &hl_irqs, irq_list) {
- if (hl->host_reset)
- hl->host_reset(host);
- }
- read_unlock_irqrestore(&hl_irqs_lock, flags);
-}
-
-void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
- void *data, size_t length)
-{
- unsigned long flags;
- struct hpsb_highlevel *hl;
- int cts = ((quadlet_t *)data)[0] >> 4;
-
- read_lock_irqsave(&hl_irqs_lock, flags);
- list_for_each_entry(hl, &hl_irqs, irq_list) {
- if (hl->fcp_request)
- hl->fcp_request(host, nodeid, direction, cts, data,
- length);
- }
- read_unlock_irqrestore(&hl_irqs_lock, flags);
-}
-
-/*
- * highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
- *
- * These functions are called to handle transactions. They are called when a
- * packet arrives. The flags argument contains the second word of the first
- * header quadlet of the incoming packet (containing transaction label, retry
- * code, transaction code and priority). These functions either return a
- * response code or a negative number. In the first case a response will be
- * generated. In the latter case, no response will be sent and the driver which
- * handled the request will send the response itself.
- */
-int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
- unsigned int length, u16 flags)
-{
- struct hpsb_address_serve *as;
- unsigned int partlength;
- int rcode = RCODE_ADDRESS_ERROR;
-
- read_lock(&addr_space_lock);
- list_for_each_entry(as, &host->addr_space, host_list) {
- if (as->start > addr)
- break;
-
- if (as->end > addr) {
- partlength = min(as->end - addr, (u64) length);
-
- if (as->op->read)
- rcode = as->op->read(host, nodeid, data,
- addr, partlength, flags);
- else
- rcode = RCODE_TYPE_ERROR;
-
- data += partlength;
- length -= partlength;
- addr += partlength;
-
- if ((rcode != RCODE_COMPLETE) || !length)
- break;
- }
- }
- read_unlock(&addr_space_lock);
-
- if (length && (rcode == RCODE_COMPLETE))
- rcode = RCODE_ADDRESS_ERROR;
- return rcode;
-}
-
-int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
- u64 addr, unsigned int length, u16 flags)
-{
- struct hpsb_address_serve *as;
- unsigned int partlength;
- int rcode = RCODE_ADDRESS_ERROR;
-
- read_lock(&addr_space_lock);
- list_for_each_entry(as, &host->addr_space, host_list) {
- if (as->start > addr)
- break;
-
- if (as->end > addr) {
- partlength = min(as->end - addr, (u64) length);
-
- if (as->op->write)
- rcode = as->op->write(host, nodeid, destid,
- data, addr, partlength,
- flags);
- else
- rcode = RCODE_TYPE_ERROR;
-
- data += partlength;
- length -= partlength;
- addr += partlength;
-
- if ((rcode != RCODE_COMPLETE) || !length)
- break;
- }
- }
- read_unlock(&addr_space_lock);
-
- if (length && (rcode == RCODE_COMPLETE))
- rcode = RCODE_ADDRESS_ERROR;
- return rcode;
-}
-
-int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
- u16 flags)
-{
- struct hpsb_address_serve *as;
- int rcode = RCODE_ADDRESS_ERROR;
-
- read_lock(&addr_space_lock);
- list_for_each_entry(as, &host->addr_space, host_list) {
- if (as->start > addr)
- break;
-
- if (as->end > addr) {
- if (as->op->lock)
- rcode = as->op->lock(host, nodeid, store, addr,
- data, arg, ext_tcode,
- flags);
- else
- rcode = RCODE_TYPE_ERROR;
- break;
- }
- }
- read_unlock(&addr_space_lock);
- return rcode;
-}
-
-int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
- u16 flags)
-{
- struct hpsb_address_serve *as;
- int rcode = RCODE_ADDRESS_ERROR;
-
- read_lock(&addr_space_lock);
-
- list_for_each_entry(as, &host->addr_space, host_list) {
- if (as->start > addr)
- break;
-
- if (as->end > addr) {
- if (as->op->lock64)
- rcode = as->op->lock64(host, nodeid, store,
- addr, data, arg,
- ext_tcode, flags);
- else
- rcode = RCODE_TYPE_ERROR;
- break;
- }
- }
- read_unlock(&addr_space_lock);
- return rcode;
-}
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
deleted file mode 100644
index 9dba89fc60ad..000000000000
--- a/drivers/ieee1394/highlevel.h
+++ /dev/null
@@ -1,141 +0,0 @@
-#ifndef IEEE1394_HIGHLEVEL_H
-#define IEEE1394_HIGHLEVEL_H
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-struct module;
-
-#include "ieee1394_types.h"
-
-struct hpsb_host;
-
-/* internal to ieee1394 core */
-struct hpsb_address_serve {
- struct list_head host_list; /* per host list */
- struct list_head hl_list; /* hpsb_highlevel list */
- const struct hpsb_address_ops *op;
- struct hpsb_host *host;
- u64 start; /* first address handled, quadlet aligned */
- u64 end; /* first address behind, quadlet aligned */
-};
-
-/* Only the following structures are of interest to actual highlevel drivers. */
-
-struct hpsb_highlevel {
- const char *name;
-
- /* Any of the following pointers can legally be NULL. */
-
- /* New host initialized. Will also be called during
- * hpsb_register_highlevel for all hosts already installed. */
- void (*add_host)(struct hpsb_host *host);
-
- /* Host about to be removed. Will also be called during
- * hpsb_unregister_highlevel once for each host. */
- void (*remove_host)(struct hpsb_host *host);
-
- /* Host experienced bus reset with possible configuration changes.
- * Note that this one may occur during interrupt/bottom half handling.
- * You can not expect to be able to do stock hpsb_reads. */
- void (*host_reset)(struct hpsb_host *host);
-
- /* A write request was received on either the FCP_COMMAND (direction =
- * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
- * contains the cts field (first byte of data). */
- void (*fcp_request)(struct hpsb_host *host, int nodeid, int direction,
- int cts, u8 *data, size_t length);
-
- /* These are initialized by the subsystem when the
- * hpsb_higlevel is registered. */
- struct list_head hl_list;
- struct list_head irq_list;
- struct list_head addr_list;
-
- struct list_head host_info_list;
- rwlock_t host_info_lock;
-};
-
-struct hpsb_address_ops {
- /*
- * Null function pointers will make the respective operation complete
- * with RCODE_TYPE_ERROR. Makes for easy to implement read-only
- * registers (just leave everything but read NULL).
- *
- * All functions shall return appropriate IEEE 1394 rcodes.
- */
-
- /* These functions have to implement block reads for themselves.
- *
- * These functions either return a response code or a negative number.
- * In the first case a response will be generated. In the latter case,
- * no response will be sent and the driver which handled the request
- * will send the response itself. */
- int (*read)(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 flags);
- int (*write)(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t *data, u64 addr, size_t length, u16 flags);
-
- /* Lock transactions: write results of ext_tcode operation into
- * *store. */
- int (*lock)(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
- u16 flags);
- int (*lock64)(struct hpsb_host *host, int nodeid, octlet_t *store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
- u16 flags);
-};
-
-void highlevel_add_host(struct hpsb_host *host);
-void highlevel_remove_host(struct hpsb_host *host);
-void highlevel_host_reset(struct hpsb_host *host);
-int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
- unsigned int length, u16 flags);
-int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
- u64 addr, unsigned int length, u16 flags);
-int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
- u16 flags);
-int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
- u16 flags);
-void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
- void *data, size_t length);
-
-/**
- * hpsb_init_highlevel - initialize a struct hpsb_highlevel
- *
- * This is only necessary if hpsb_get_hostinfo_bykey can be called
- * before hpsb_register_highlevel.
- */
-static inline void hpsb_init_highlevel(struct hpsb_highlevel *hl)
-{
- rwlock_init(&hl->host_info_lock);
- INIT_LIST_HEAD(&hl->host_info_list);
-}
-void hpsb_register_highlevel(struct hpsb_highlevel *hl);
-void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
-
-u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
- struct hpsb_host *host,
- const struct hpsb_address_ops *ops,
- u64 size, u64 alignment,
- u64 start, u64 end);
-int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- const struct hpsb_address_ops *ops,
- u64 start, u64 end);
-int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- u64 start);
-
-void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
- size_t data_size);
-void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
- unsigned long key);
-void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
-int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
- void *data);
-
-#endif /* IEEE1394_HIGHLEVEL_H */
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
deleted file mode 100644
index e947d8ffac85..000000000000
--- a/drivers/ieee1394/hosts.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Low level (host adapter) management.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- * Copyright (C) 1999 Emanuel Pirker
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-#include <linux/mutex.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "nodemgr.h"
-#include "csr.h"
-#include "config_roms.h"
-
-
-static void delayed_reset_bus(struct work_struct *work)
-{
- struct hpsb_host *host =
- container_of(work, struct hpsb_host, delayed_reset.work);
- u8 generation = host->csr.generation + 1;
-
- /* The generation field rolls over to 2 rather than 0 per IEEE
- * 1394a-2000. */
- if (generation > 0xf || generation < 2)
- generation = 2;
-
- csr_set_bus_info_generation(host->csr.rom, generation);
- if (csr1212_generate_csr_image(host->csr.rom) != CSR1212_SUCCESS) {
- /* CSR image creation failed.
- * Reset generation field and do not issue a bus reset. */
- csr_set_bus_info_generation(host->csr.rom,
- host->csr.generation);
- return;
- }
-
- host->csr.generation = generation;
-
- host->update_config_rom = 0;
- if (host->driver->set_hw_config_rom)
- host->driver->set_hw_config_rom(host,
- host->csr.rom->bus_info_data);
-
- host->csr.gen_timestamp[host->csr.generation] = jiffies;
- hpsb_reset_bus(host, SHORT_RESET);
-}
-
-static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
-{
- return 0;
-}
-
-static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
-{
- return -1;
-}
-
-static int dummy_isoctl(struct hpsb_iso *iso, enum isoctl_cmd command,
- unsigned long arg)
-{
- return -1;
-}
-
-static struct hpsb_host_driver dummy_driver = {
- .transmit_packet = dummy_transmit_packet,
- .devctl = dummy_devctl,
- .isoctl = dummy_isoctl
-};
-
-static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
-{
- int *hostnum = __data;
-
- if (host->id == *hostnum)
- return 1;
-
- return 0;
-}
-
-static DEFINE_MUTEX(host_num_alloc);
-
-/**
- * hpsb_alloc_host - allocate a new host controller.
- * @drv: the driver that will manage the host controller
- * @extra: number of extra bytes to allocate for the driver
- *
- * Allocate a &hpsb_host and initialize the general subsystem specific
- * fields. If the driver needs to store per host data, as drivers
- * usually do, the amount of memory required can be specified by the
- * @extra parameter. Once allocated, the driver should initialize the
- * driver specific parts, enable the controller and make it available
- * to the general subsystem using hpsb_add_host().
- *
- * Return Value: a pointer to the &hpsb_host if successful, %NULL if
- * no memory was available.
- */
-struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
- struct device *dev)
-{
- struct hpsb_host *h;
- int i;
- int hostnum = 0;
-
- h = kzalloc(sizeof(*h) + extra, GFP_KERNEL);
- if (!h)
- return NULL;
-
- h->csr.rom = csr1212_create_csr(&csr_bus_ops, CSR_BUS_INFO_SIZE, h);
- if (!h->csr.rom)
- goto fail;
-
- h->hostdata = h + 1;
- h->driver = drv;
-
- INIT_LIST_HEAD(&h->pending_packets);
- INIT_LIST_HEAD(&h->addr_space);
-
- for (i = 2; i < 16; i++)
- h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
-
- atomic_set(&h->generation, 0);
-
- INIT_DELAYED_WORK(&h->delayed_reset, delayed_reset_bus);
-
- init_timer(&h->timeout);
- h->timeout.data = (unsigned long) h;
- h->timeout.function = abort_timedouts;
- h->timeout_interval = HZ / 20; /* 50ms, half of minimum SPLIT_TIMEOUT */
-
- h->topology_map = h->csr.topology_map + 3;
- h->speed_map = (u8 *)(h->csr.speed_map + 2);
-
- mutex_lock(&host_num_alloc);
- while (nodemgr_for_each_host(&hostnum, alloc_hostnum_cb))
- hostnum++;
- mutex_unlock(&host_num_alloc);
- h->id = hostnum;
-
- memcpy(&h->device, &nodemgr_dev_template_host, sizeof(h->device));
- h->device.parent = dev;
- set_dev_node(&h->device, dev_to_node(dev));
- dev_set_name(&h->device, "fw-host%d", h->id);
-
- h->host_dev.parent = &h->device;
- h->host_dev.class = &hpsb_host_class;
- dev_set_name(&h->host_dev, "fw-host%d", h->id);
-
- if (device_register(&h->device))
- goto fail;
- if (device_register(&h->host_dev)) {
- device_unregister(&h->device);
- goto fail;
- }
- get_device(&h->device);
-
- return h;
-
-fail:
- kfree(h);
- return NULL;
-}
-
-int hpsb_add_host(struct hpsb_host *host)
-{
- if (hpsb_default_host_entry(host))
- return -ENOMEM;
-
- highlevel_add_host(host);
- return 0;
-}
-
-void hpsb_resume_host(struct hpsb_host *host)
-{
- if (host->driver->set_hw_config_rom)
- host->driver->set_hw_config_rom(host,
- host->csr.rom->bus_info_data);
- host->driver->devctl(host, RESET_BUS, SHORT_RESET);
-}
-
-void hpsb_remove_host(struct hpsb_host *host)
-{
- host->is_shutdown = 1;
-
- cancel_delayed_work(&host->delayed_reset);
- flush_scheduled_work();
-
- host->driver = &dummy_driver;
- highlevel_remove_host(host);
-
- device_unregister(&host->host_dev);
- device_unregister(&host->device);
-}
-
-/**
- * hpsb_update_config_rom_image - updates configuration ROM image of a host
- *
- * Updates the configuration ROM image of a host. rom_version must be the
- * current version, otherwise it will fail with return value -1. If this
- * host does not support config-rom-update, it will return -%EINVAL.
- * Return value 0 indicates success.
- */
-int hpsb_update_config_rom_image(struct hpsb_host *host)
-{
- unsigned long reset_delay;
- int next_gen = host->csr.generation + 1;
-
- if (!host->update_config_rom)
- return -EINVAL;
-
- if (next_gen > 0xf)
- next_gen = 2;
-
- /* Stop the delayed interrupt, we're about to change the config rom and
- * it would be a waste to do a bus reset twice. */
- cancel_delayed_work(&host->delayed_reset);
-
- /* IEEE 1394a-2000 prohibits using the same generation number
- * twice in a 60 second period. */
- if (time_before(jiffies, host->csr.gen_timestamp[next_gen] + 60 * HZ))
- /* Wait 60 seconds from the last time this generation number was
- * used. */
- reset_delay =
- (60 * HZ) + host->csr.gen_timestamp[next_gen] - jiffies;
- else
- /* Wait 1 second in case some other code wants to change the
- * Config ROM in the near future. */
- reset_delay = HZ;
-
- PREPARE_DELAYED_WORK(&host->delayed_reset, delayed_reset_bus);
- schedule_delayed_work(&host->delayed_reset, reset_delay);
-
- return 0;
-}
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
deleted file mode 100644
index 49c359022c54..000000000000
--- a/drivers/ieee1394/hosts.h
+++ /dev/null
@@ -1,201 +0,0 @@
-#ifndef _IEEE1394_HOSTS_H
-#define _IEEE1394_HOSTS_H
-
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/types.h>
-#include <linux/workqueue.h>
-#include <asm/atomic.h>
-
-struct pci_dev;
-struct module;
-
-#include "ieee1394_types.h"
-#include "csr.h"
-#include "highlevel.h"
-
-struct hpsb_packet;
-struct hpsb_iso;
-
-struct hpsb_host {
- struct list_head host_list;
-
- void *hostdata;
-
- atomic_t generation;
-
- struct list_head pending_packets;
- struct timer_list timeout;
- unsigned long timeout_interval;
-
- int node_count; /* number of identified nodes on this bus */
- int selfid_count; /* total number of SelfIDs received */
- int nodes_active; /* number of nodes with active link layer */
-
- nodeid_t node_id; /* node ID of this host */
- nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
- nodeid_t busmgr_id; /* ID of this bus' bus manager */
-
- /* this nodes state */
- unsigned in_bus_reset:1;
- unsigned is_shutdown:1;
- unsigned resume_packet_sent:1;
-
- /* this nodes' duties on the bus */
- unsigned is_root:1;
- unsigned is_cycmst:1;
- unsigned is_irm:1;
- unsigned is_busmgr:1;
-
- int reset_retries;
- quadlet_t *topology_map;
- u8 *speed_map;
-
- int id;
- struct hpsb_host_driver *driver;
- struct pci_dev *pdev;
- struct device device;
- struct device host_dev;
-
- struct delayed_work delayed_reset;
- unsigned config_roms:31;
- unsigned update_config_rom:1;
-
- struct list_head addr_space;
- u64 low_addr_space; /* upper bound of physical DMA area */
- u64 middle_addr_space; /* upper bound of posted write area */
-
- u8 speed[ALL_NODES]; /* speed between each node and local node */
-
- /* per node tlabel allocation */
- u8 next_tl[ALL_NODES];
- struct { DECLARE_BITMAP(map, 64); } tl_pool[ALL_NODES];
-
- struct csr_control csr;
-
- struct hpsb_address_serve dummy_zero_addr;
- struct hpsb_address_serve dummy_max_addr;
-};
-
-enum devctl_cmd {
- /* Host is requested to reset its bus and cancel all outstanding async
- * requests. If arg == 1, it shall also attempt to become root on the
- * bus. Return void. */
- RESET_BUS,
-
- /* Arg is void, return value is the hardware cycle counter value. */
- GET_CYCLE_COUNTER,
-
- /* Set the hardware cycle counter to the value in arg, return void.
- * FIXME - setting is probably not required. */
- SET_CYCLE_COUNTER,
-
- /* Configure hardware for new bus ID in arg, return void. */
- SET_BUS_ID,
-
- /* If arg true, start sending cycle start packets, stop if arg == 0.
- * Return void. */
- ACT_CYCLE_MASTER,
-
- /* Cancel all outstanding async requests without resetting the bus.
- * Return void. */
- CANCEL_REQUESTS,
-};
-
-enum isoctl_cmd {
- /* rawiso API - see iso.h for the meanings of these commands
- * (they correspond exactly to the hpsb_iso_* API functions)
- * INIT = allocate resources
- * START = begin transmission/reception
- * STOP = halt transmission/reception
- * QUEUE/RELEASE = produce/consume packets
- * SHUTDOWN = deallocate resources
- */
-
- XMIT_INIT,
- XMIT_START,
- XMIT_STOP,
- XMIT_QUEUE,
- XMIT_SHUTDOWN,
-
- RECV_INIT,
- RECV_LISTEN_CHANNEL, /* multi-channel only */
- RECV_UNLISTEN_CHANNEL, /* multi-channel only */
- RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */
- RECV_START,
- RECV_STOP,
- RECV_RELEASE,
- RECV_SHUTDOWN,
- RECV_FLUSH
-};
-
-enum reset_types {
- /* 166 microsecond reset -- only type of reset available on
- non-1394a capable controllers */
- LONG_RESET,
-
- /* Short (arbitrated) reset -- only available on 1394a capable
- controllers */
- SHORT_RESET,
-
- /* Variants that set force_root before issueing the bus reset */
- LONG_RESET_FORCE_ROOT, SHORT_RESET_FORCE_ROOT,
-
- /* Variants that clear force_root before issueing the bus reset */
- LONG_RESET_NO_FORCE_ROOT, SHORT_RESET_NO_FORCE_ROOT
-};
-
-struct hpsb_host_driver {
- struct module *owner;
- const char *name;
-
- /* The hardware driver may optionally support a function that is used
- * to set the hardware ConfigROM if the hardware supports handling
- * reads to the ConfigROM on its own. */
- void (*set_hw_config_rom)(struct hpsb_host *host,
- __be32 *config_rom);
-
- /* This function shall implement packet transmission based on
- * packet->type. It shall CRC both parts of the packet (unless
- * packet->type == raw) and do byte-swapping as necessary or instruct
- * the hardware to do so. It can return immediately after the packet
- * was queued for sending. After sending, hpsb_sent_packet() has to be
- * called. Return 0 on success, negative errno on failure.
- * NOTE: The function must be callable in interrupt context.
- */
- int (*transmit_packet)(struct hpsb_host *host,
- struct hpsb_packet *packet);
-
- /* This function requests miscellanous services from the driver, see
- * above for command codes and expected actions. Return -1 for unknown
- * command, though that should never happen.
- */
- int (*devctl)(struct hpsb_host *host, enum devctl_cmd command, int arg);
-
- /* ISO transmission/reception functions. Return 0 on success, -1
- * (or -EXXX errno code) on failure. If the low-level driver does not
- * support the new ISO API, set isoctl to NULL.
- */
- int (*isoctl)(struct hpsb_iso *iso, enum isoctl_cmd command,
- unsigned long arg);
-
- /* This function is mainly to redirect local CSR reads/locks to the iso
- * management registers (bus manager id, bandwidth available, channels
- * available) to the hardware registers in OHCI. reg is 0,1,2,3 for bus
- * mgr, bwdth avail, ch avail hi, ch avail lo respectively (the same ids
- * as OHCI uses). data and compare are the new data and expected data
- * respectively, return value is the old value.
- */
- quadlet_t (*hw_csr_reg) (struct hpsb_host *host, int reg,
- quadlet_t data, quadlet_t compare);
-};
-
-struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
- struct device *dev);
-int hpsb_add_host(struct hpsb_host *host);
-void hpsb_resume_host(struct hpsb_host *host);
-void hpsb_remove_host(struct hpsb_host *host);
-int hpsb_update_config_rom_image(struct hpsb_host *host);
-
-#endif /* _IEEE1394_HOSTS_H */
diff --git a/drivers/ieee1394/ieee1394-ioctl.h b/drivers/ieee1394/ieee1394-ioctl.h
deleted file mode 100644
index 46878fef136c..000000000000
--- a/drivers/ieee1394/ieee1394-ioctl.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Base file for all ieee1394 ioctl's.
- * Linux-1394 has allocated base '#' with a range of 0x00-0x3f.
- */
-
-#ifndef __IEEE1394_IOCTL_H
-#define __IEEE1394_IOCTL_H
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-/* DV1394 Gets 10 */
-
-/* Get the driver ready to transmit video. pass a struct dv1394_init* as
- * the parameter (see below), or NULL to get default parameters */
-#define DV1394_IOC_INIT _IOW('#', 0x06, struct dv1394_init)
-
-/* Stop transmitting video and free the ringbuffer */
-#define DV1394_IOC_SHUTDOWN _IO ('#', 0x07)
-
-/* Submit N new frames to be transmitted, where the index of the first new
- * frame is first_clear_buffer, and the index of the last new frame is
- * (first_clear_buffer + N) % n_frames */
-#define DV1394_IOC_SUBMIT_FRAMES _IO ('#', 0x08)
-
-/* Block until N buffers are clear (pass N as the parameter) Because we
- * re-transmit the last frame on underrun, there will at most be n_frames
- * - 1 clear frames at any time */
-#define DV1394_IOC_WAIT_FRAMES _IO ('#', 0x09)
-
-/* Capture new frames that have been received, where the index of the
- * first new frame is first_clear_buffer, and the index of the last new
- * frame is (first_clear_buffer + N) % n_frames */
-#define DV1394_IOC_RECEIVE_FRAMES _IO ('#', 0x0a)
-
-/* Tell card to start receiving DMA */
-#define DV1394_IOC_START_RECEIVE _IO ('#', 0x0b)
-
-/* Pass a struct dv1394_status* as the parameter */
-#define DV1394_IOC_GET_STATUS _IOR('#', 0x0c, struct dv1394_status)
-
-
-/* Video1394 Gets 10 */
-
-#define VIDEO1394_IOC_LISTEN_CHANNEL \
- _IOWR('#', 0x10, struct video1394_mmap)
-#define VIDEO1394_IOC_UNLISTEN_CHANNEL \
- _IOW ('#', 0x11, int)
-#define VIDEO1394_IOC_LISTEN_QUEUE_BUFFER \
- _IOW ('#', 0x12, struct video1394_wait)
-#define VIDEO1394_IOC_LISTEN_WAIT_BUFFER \
- _IOWR('#', 0x13, struct video1394_wait)
-#define VIDEO1394_IOC_TALK_CHANNEL \
- _IOWR('#', 0x14, struct video1394_mmap)
-#define VIDEO1394_IOC_UNTALK_CHANNEL \
- _IOW ('#', 0x15, int)
-/*
- * This one is broken: it really wanted
- * "sizeof (struct video1394_wait) + sizeof (struct video1394_queue_variable)"
- * but got just a "size_t"
- */
-#define VIDEO1394_IOC_TALK_QUEUE_BUFFER \
- _IOW ('#', 0x16, size_t)
-#define VIDEO1394_IOC_TALK_WAIT_BUFFER \
- _IOW ('#', 0x17, struct video1394_wait)
-#define VIDEO1394_IOC_LISTEN_POLL_BUFFER \
- _IOWR('#', 0x18, struct video1394_wait)
-
-
-/* Raw1394's ISO interface */
-#define RAW1394_IOC_ISO_XMIT_INIT \
- _IOW ('#', 0x1a, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_RECV_INIT \
- _IOWR('#', 0x1b, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_RECV_START \
- _IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3)
-#define RAW1394_IOC_ISO_XMIT_START \
- _IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2)
-#define RAW1394_IOC_ISO_XMIT_RECV_STOP \
- _IO ('#', 0x1e)
-#define RAW1394_IOC_ISO_GET_STATUS \
- _IOR ('#', 0x1f, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_SHUTDOWN \
- _IO ('#', 0x20)
-#define RAW1394_IOC_ISO_QUEUE_ACTIVITY \
- _IO ('#', 0x21)
-#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL \
- _IOW ('#', 0x22, unsigned char)
-#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL \
- _IOW ('#', 0x23, unsigned char)
-#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK \
- _IOW ('#', 0x24, __u64)
-#define RAW1394_IOC_ISO_RECV_PACKETS \
- _IOW ('#', 0x25, struct raw1394_iso_packets)
-#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS \
- _IOW ('#', 0x26, unsigned int)
-#define RAW1394_IOC_ISO_XMIT_PACKETS \
- _IOW ('#', 0x27, struct raw1394_iso_packets)
-#define RAW1394_IOC_ISO_XMIT_SYNC \
- _IO ('#', 0x28)
-#define RAW1394_IOC_ISO_RECV_FLUSH \
- _IO ('#', 0x29)
-#define RAW1394_IOC_GET_CYCLE_TIMER \
- _IOR ('#', 0x30, struct raw1394_cycle_timer)
-
-#endif /* __IEEE1394_IOCTL_H */
diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
deleted file mode 100644
index af320e2c5079..000000000000
--- a/drivers/ieee1394/ieee1394.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Generic IEEE 1394 definitions
- */
-
-#ifndef _IEEE1394_IEEE1394_H
-#define _IEEE1394_IEEE1394_H
-
-#define TCODE_WRITEQ 0x0
-#define TCODE_WRITEB 0x1
-#define TCODE_WRITE_RESPONSE 0x2
-#define TCODE_READQ 0x4
-#define TCODE_READB 0x5
-#define TCODE_READQ_RESPONSE 0x6
-#define TCODE_READB_RESPONSE 0x7
-#define TCODE_CYCLE_START 0x8
-#define TCODE_LOCK_REQUEST 0x9
-#define TCODE_ISO_DATA 0xa
-#define TCODE_STREAM_DATA 0xa
-#define TCODE_LOCK_RESPONSE 0xb
-
-#define RCODE_COMPLETE 0x0
-#define RCODE_CONFLICT_ERROR 0x4
-#define RCODE_DATA_ERROR 0x5
-#define RCODE_TYPE_ERROR 0x6
-#define RCODE_ADDRESS_ERROR 0x7
-
-#define EXTCODE_MASK_SWAP 0x1
-#define EXTCODE_COMPARE_SWAP 0x2
-#define EXTCODE_FETCH_ADD 0x3
-#define EXTCODE_LITTLE_ADD 0x4
-#define EXTCODE_BOUNDED_ADD 0x5
-#define EXTCODE_WRAP_ADD 0x6
-
-#define ACK_COMPLETE 0x1
-#define ACK_PENDING 0x2
-#define ACK_BUSY_X 0x4
-#define ACK_BUSY_A 0x5
-#define ACK_BUSY_B 0x6
-#define ACK_TARDY 0xb
-#define ACK_CONFLICT_ERROR 0xc
-#define ACK_DATA_ERROR 0xd
-#define ACK_TYPE_ERROR 0xe
-#define ACK_ADDRESS_ERROR 0xf
-
-/* Non-standard "ACK codes" for internal use */
-#define ACKX_NONE (-1)
-#define ACKX_SEND_ERROR (-2)
-#define ACKX_ABORTED (-3)
-#define ACKX_TIMEOUT (-4)
-
-#define IEEE1394_SPEED_100 0x00
-#define IEEE1394_SPEED_200 0x01
-#define IEEE1394_SPEED_400 0x02
-#define IEEE1394_SPEED_800 0x03
-#define IEEE1394_SPEED_1600 0x04
-#define IEEE1394_SPEED_3200 0x05
-#define IEEE1394_SPEED_MAX IEEE1394_SPEED_3200
-
-/* Maps speed values above to a string representation */
-extern const char *hpsb_speedto_str[];
-
-/* 1394a cable PHY packets */
-#define SELFID_PWRCL_NO_POWER 0x0
-#define SELFID_PWRCL_PROVIDE_15W 0x1
-#define SELFID_PWRCL_PROVIDE_30W 0x2
-#define SELFID_PWRCL_PROVIDE_45W 0x3
-#define SELFID_PWRCL_USE_1W 0x4
-#define SELFID_PWRCL_USE_3W 0x5
-#define SELFID_PWRCL_USE_6W 0x6
-#define SELFID_PWRCL_USE_10W 0x7
-
-#define SELFID_PORT_CHILD 0x3
-#define SELFID_PORT_PARENT 0x2
-#define SELFID_PORT_NCONN 0x1
-#define SELFID_PORT_NONE 0x0
-
-#define SELFID_SPEED_UNKNOWN 0x3 /* 1394b PHY */
-
-#define PHYPACKET_LINKON 0x40000000
-#define PHYPACKET_PHYCONFIG_R 0x00800000
-#define PHYPACKET_PHYCONFIG_T 0x00400000
-#define EXTPHYPACKET_TYPE_PING 0x00000000
-#define EXTPHYPACKET_TYPE_REMOTEACCESS_BASE 0x00040000
-#define EXTPHYPACKET_TYPE_REMOTEACCESS_PAGED 0x00140000
-#define EXTPHYPACKET_TYPE_REMOTEREPLY_BASE 0x000C0000
-#define EXTPHYPACKET_TYPE_REMOTEREPLY_PAGED 0x001C0000
-#define EXTPHYPACKET_TYPE_REMOTECOMMAND 0x00200000
-#define EXTPHYPACKET_TYPE_REMOTECONFIRMATION 0x00280000
-#define EXTPHYPACKET_TYPE_RESUME 0x003C0000
-
-#define EXTPHYPACKET_TYPEMASK 0xC0FC0000
-
-#define PHYPACKET_PORT_SHIFT 24
-#define PHYPACKET_GAPCOUNT_SHIFT 16
-
-/* 1394a PHY register map bitmasks */
-#define PHY_00_PHYSICAL_ID 0xFC
-#define PHY_00_R 0x02 /* Root */
-#define PHY_00_PS 0x01 /* Power Status*/
-#define PHY_01_RHB 0x80 /* Root Hold-Off */
-#define PHY_01_IBR 0x80 /* Initiate Bus Reset */
-#define PHY_01_GAP_COUNT 0x3F
-#define PHY_02_EXTENDED 0xE0 /* 0x7 for 1394a-compliant PHY */
-#define PHY_02_TOTAL_PORTS 0x1F
-#define PHY_03_MAX_SPEED 0xE0
-#define PHY_03_DELAY 0x0F
-#define PHY_04_LCTRL 0x80 /* Link Active Report Control */
-#define PHY_04_CONTENDER 0x40
-#define PHY_04_JITTER 0x38
-#define PHY_04_PWR_CLASS 0x07 /* Power Class */
-#define PHY_05_WATCHDOG 0x80
-#define PHY_05_ISBR 0x40 /* Initiate Short Bus Reset */
-#define PHY_05_LOOP 0x20 /* Loop Detect */
-#define PHY_05_PWR_FAIL 0x10 /* Cable Power Failure Detect */
-#define PHY_05_TIMEOUT 0x08 /* Arbitration State Machine Timeout */
-#define PHY_05_PORT_EVENT 0x04 /* Port Event Detect */
-#define PHY_05_ENAB_ACCEL 0x02 /* Enable Arbitration Acceleration */
-#define PHY_05_ENAB_MULTI 0x01 /* Ena. Multispeed Packet Concatenation */
-
-#include <asm/byteorder.h>
-
-/* '1' '3' '9' '4' in ASCII */
-#define IEEE1394_BUSID_MAGIC cpu_to_be32(0x31333934)
-
-#ifdef __BIG_ENDIAN_BITFIELD
-
-struct selfid {
- u32 packet_identifier:2; /* always binary 10 */
- u32 phy_id:6;
- /* byte */
- u32 extended:1; /* if true is struct ext_selfid */
- u32 link_active:1;
- u32 gap_count:6;
- /* byte */
- u32 speed:2;
- u32 phy_delay:2;
- u32 contender:1;
- u32 power_class:3;
- /* byte */
- u32 port0:2;
- u32 port1:2;
- u32 port2:2;
- u32 initiated_reset:1;
- u32 more_packets:1;
-} __attribute__((packed));
-
-struct ext_selfid {
- u32 packet_identifier:2; /* always binary 10 */
- u32 phy_id:6;
- /* byte */
- u32 extended:1; /* if false is struct selfid */
- u32 seq_nr:3;
- u32 reserved:2;
- u32 porta:2;
- /* byte */
- u32 portb:2;
- u32 portc:2;
- u32 portd:2;
- u32 porte:2;
- /* byte */
- u32 portf:2;
- u32 portg:2;
- u32 porth:2;
- u32 reserved2:1;
- u32 more_packets:1;
-} __attribute__((packed));
-
-#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
-
-/*
- * Note: these mean to be bit fields of a big endian SelfID as seen on a little
- * endian machine. Without swapping.
- */
-
-struct selfid {
- u32 phy_id:6;
- u32 packet_identifier:2; /* always binary 10 */
- /* byte */
- u32 gap_count:6;
- u32 link_active:1;
- u32 extended:1; /* if true is struct ext_selfid */
- /* byte */
- u32 power_class:3;
- u32 contender:1;
- u32 phy_delay:2;
- u32 speed:2;
- /* byte */
- u32 more_packets:1;
- u32 initiated_reset:1;
- u32 port2:2;
- u32 port1:2;
- u32 port0:2;
-} __attribute__((packed));
-
-struct ext_selfid {
- u32 phy_id:6;
- u32 packet_identifier:2; /* always binary 10 */
- /* byte */
- u32 porta:2;
- u32 reserved:2;
- u32 seq_nr:3;
- u32 extended:1; /* if false is struct selfid */
- /* byte */
- u32 porte:2;
- u32 portd:2;
- u32 portc:2;
- u32 portb:2;
- /* byte */
- u32 more_packets:1;
- u32 reserved2:1;
- u32 porth:2;
- u32 portg:2;
- u32 portf:2;
-} __attribute__((packed));
-
-#else
-#error What? PDP endian?
-#endif /* __BIG_ENDIAN_BITFIELD */
-
-#endif /* _IEEE1394_IEEE1394_H */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
deleted file mode 100644
index 872338003721..000000000000
--- a/drivers/ieee1394/ieee1394_core.c
+++ /dev/null
@@ -1,1380 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Core support: hpsb_packet management, packet handling and forwarding to
- * highlevel or lowlevel code
- *
- * Copyright (C) 1999, 2000 Andreas E. Bombe
- * 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * loopback functionality in hpsb_send_packet
- * allow highlevel drivers to disable automatic response generation
- * and to generate responses themselves (deferred)
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/bitops.h>
-#include <linux/kdev_t.h>
-#include <linux/freezer.h>
-#include <linux/suspend.h>
-#include <linux/kthread.h>
-#include <linux/preempt.h>
-#include <linux/time.h>
-
-#include <asm/system.h>
-#include <asm/byteorder.h>
-
-#include "ieee1394_types.h"
-#include "ieee1394.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "ieee1394_transactions.h"
-#include "csr.h"
-#include "nodemgr.h"
-#include "dma.h"
-#include "iso.h"
-#include "config_roms.h"
-
-/*
- * Disable the nodemgr detection and config rom reading functionality.
- */
-static int disable_nodemgr;
-module_param(disable_nodemgr, int, 0444);
-MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
-
-/* Disable Isochronous Resource Manager functionality */
-int hpsb_disable_irm = 0;
-module_param_named(disable_irm, hpsb_disable_irm, bool, 0444);
-MODULE_PARM_DESC(disable_irm,
- "Disable Isochronous Resource Manager functionality.");
-
-/* We are GPL, so treat us special */
-MODULE_LICENSE("GPL");
-
-/* Some globals used */
-const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };
-struct class *hpsb_protocol_class;
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-static void dump_packet(const char *text, quadlet_t *data, int size, int speed)
-{
- int i;
-
- size /= 4;
- size = (size > 4 ? 4 : size);
-
- printk(KERN_DEBUG "ieee1394: %s", text);
- if (speed > -1 && speed < 6)
- printk(" at %s", hpsb_speedto_str[speed]);
- printk(":");
- for (i = 0; i < size; i++)
- printk(" %08x", data[i]);
- printk("\n");
-}
-#else
-#define dump_packet(a,b,c,d) do {} while (0)
-#endif
-
-static void abort_requests(struct hpsb_host *host);
-static void queue_packet_complete(struct hpsb_packet *packet);
-
-
-/**
- * hpsb_set_packet_complete_task - set task that runs when a packet completes
- * @packet: the packet whose completion we want the task added to
- * @routine: function to call
- * @data: data (if any) to pass to the above function
- *
- * Set the task that runs when a packet completes. You cannot call this more
- * than once on a single packet before it is sent.
- *
- * Typically, the complete @routine is responsible to call hpsb_free_packet().
- */
-void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
- void (*routine)(void *), void *data)
-{
- WARN_ON(packet->complete_routine != NULL);
- packet->complete_routine = routine;
- packet->complete_data = data;
- return;
-}
-
-/**
- * hpsb_alloc_packet - allocate new packet structure
- * @data_size: size of the data block to be allocated, in bytes
- *
- * This function allocates, initializes and returns a new &struct hpsb_packet.
- * It can be used in interrupt context. A header block is always included and
- * initialized with zeros. Its size is big enough to contain all possible 1394
- * headers. The data block is only allocated if @data_size is not zero.
- *
- * For packets for which responses will be received the @data_size has to be big
- * enough to contain the response's data block since no further allocation
- * occurs at response matching time.
- *
- * The packet's generation value will be set to the current generation number
- * for ease of use. Remember to overwrite it with your own recorded generation
- * number if you can not be sure that your code will not race with a bus reset.
- *
- * Return value: A pointer to a &struct hpsb_packet or NULL on allocation
- * failure.
- */
-struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
-{
- struct hpsb_packet *packet;
-
- data_size = ((data_size + 3) & ~3);
-
- packet = kzalloc(sizeof(*packet) + data_size, GFP_ATOMIC);
- if (!packet)
- return NULL;
-
- packet->state = hpsb_unused;
- packet->generation = -1;
- INIT_LIST_HEAD(&packet->driver_list);
- INIT_LIST_HEAD(&packet->queue);
- atomic_set(&packet->refcnt, 1);
-
- if (data_size) {
- packet->data = packet->embedded_data;
- packet->allocated_data_size = data_size;
- }
- return packet;
-}
-
-/**
- * hpsb_free_packet - free packet and data associated with it
- * @packet: packet to free (is NULL safe)
- *
- * Frees @packet->data only if it was allocated through hpsb_alloc_packet().
- */
-void hpsb_free_packet(struct hpsb_packet *packet)
-{
- if (packet && atomic_dec_and_test(&packet->refcnt)) {
- BUG_ON(!list_empty(&packet->driver_list) ||
- !list_empty(&packet->queue));
- kfree(packet);
- }
-}
-
-/**
- * hpsb_reset_bus - initiate bus reset on the given host
- * @host: host controller whose bus to reset
- * @type: one of enum reset_types
- *
- * Returns 1 if bus reset already in progress, 0 otherwise.
- */
-int hpsb_reset_bus(struct hpsb_host *host, int type)
-{
- if (!host->in_bus_reset) {
- host->driver->devctl(host, RESET_BUS, type);
- return 0;
- } else {
- return 1;
- }
-}
-
-/**
- * hpsb_read_cycle_timer - read cycle timer register and system time
- * @host: host whose isochronous cycle timer register is read
- * @cycle_timer: address of bitfield to return the register contents
- * @local_time: address to return the system time
- *
- * The format of * @cycle_timer, is described in OHCI 1.1 clause 5.13. This
- * format is also read from non-OHCI controllers. * @local_time contains the
- * system time in microseconds since the Epoch, read at the moment when the
- * cycle timer was read.
- *
- * Return value: 0 for success or error number otherwise.
- */
-int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
- u64 *local_time)
-{
- int ctr;
- struct timeval tv;
- unsigned long flags;
-
- if (!host || !cycle_timer || !local_time)
- return -EINVAL;
-
- preempt_disable();
- local_irq_save(flags);
-
- ctr = host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
- if (ctr)
- do_gettimeofday(&tv);
-
- local_irq_restore(flags);
- preempt_enable();
-
- if (!ctr)
- return -EIO;
- *cycle_timer = ctr;
- *local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
- return 0;
-}
-
-/**
- * hpsb_bus_reset - notify a bus reset to the core
- *
- * For host driver module usage. Safe to use in interrupt context, although
- * quite complex; so you may want to run it in the bottom rather than top half.
- *
- * Returns 1 if bus reset already in progress, 0 otherwise.
- */
-int hpsb_bus_reset(struct hpsb_host *host)
-{
- if (host->in_bus_reset) {
- HPSB_NOTICE("%s called while bus reset already in progress",
- __func__);
- return 1;
- }
-
- abort_requests(host);
- host->in_bus_reset = 1;
- host->irm_id = -1;
- host->is_irm = 0;
- host->busmgr_id = -1;
- host->is_busmgr = 0;
- host->is_cycmst = 0;
- host->node_count = 0;
- host->selfid_count = 0;
-
- return 0;
-}
-
-
-/*
- * Verify num_of_selfids SelfIDs and return number of nodes. Return zero in
- * case verification failed.
- */
-static int check_selfids(struct hpsb_host *host)
-{
- int nodeid = -1;
- int rest_of_selfids = host->selfid_count;
- struct selfid *sid = (struct selfid *)host->topology_map;
- struct ext_selfid *esid;
- int esid_seq = 23;
-
- host->nodes_active = 0;
-
- while (rest_of_selfids--) {
- if (!sid->extended) {
- nodeid++;
- esid_seq = 0;
-
- if (sid->phy_id != nodeid) {
- HPSB_INFO("SelfIDs failed monotony check with "
- "%d", sid->phy_id);
- return 0;
- }
-
- if (sid->link_active) {
- host->nodes_active++;
- if (sid->contender)
- host->irm_id = LOCAL_BUS | sid->phy_id;
- }
- } else {
- esid = (struct ext_selfid *)sid;
-
- if ((esid->phy_id != nodeid)
- || (esid->seq_nr != esid_seq)) {
- HPSB_INFO("SelfIDs failed monotony check with "
- "%d/%d", esid->phy_id, esid->seq_nr);
- return 0;
- }
- esid_seq++;
- }
- sid++;
- }
-
- esid = (struct ext_selfid *)(sid - 1);
- while (esid->extended) {
- if ((esid->porta == SELFID_PORT_PARENT) ||
- (esid->portb == SELFID_PORT_PARENT) ||
- (esid->portc == SELFID_PORT_PARENT) ||
- (esid->portd == SELFID_PORT_PARENT) ||
- (esid->porte == SELFID_PORT_PARENT) ||
- (esid->portf == SELFID_PORT_PARENT) ||
- (esid->portg == SELFID_PORT_PARENT) ||
- (esid->porth == SELFID_PORT_PARENT)) {
- HPSB_INFO("SelfIDs failed root check on "
- "extended SelfID");
- return 0;
- }
- esid--;
- }
-
- sid = (struct selfid *)esid;
- if ((sid->port0 == SELFID_PORT_PARENT) ||
- (sid->port1 == SELFID_PORT_PARENT) ||
- (sid->port2 == SELFID_PORT_PARENT)) {
- HPSB_INFO("SelfIDs failed root check");
- return 0;
- }
-
- host->node_count = nodeid + 1;
- return 1;
-}
-
-static void build_speed_map(struct hpsb_host *host, int nodecount)
-{
- u8 cldcnt[nodecount];
- u8 *map = host->speed_map;
- u8 *speedcap = host->speed;
- u8 local_link_speed = host->csr.lnk_spd;
- struct selfid *sid;
- struct ext_selfid *esid;
- int i, j, n;
-
- for (i = 0; i < (nodecount * 64); i += 64) {
- for (j = 0; j < nodecount; j++) {
- map[i+j] = IEEE1394_SPEED_MAX;
- }
- }
-
- for (i = 0; i < nodecount; i++) {
- cldcnt[i] = 0;
- }
-
- /* find direct children count and speed */
- for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],
- n = nodecount - 1;
- (void *)sid >= (void *)host->topology_map; sid--) {
- if (sid->extended) {
- esid = (struct ext_selfid *)sid;
-
- if (esid->porta == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->portb == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->portc == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->portd == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->porte == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->portf == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->portg == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->porth == SELFID_PORT_CHILD) cldcnt[n]++;
- } else {
- if (sid->port0 == SELFID_PORT_CHILD) cldcnt[n]++;
- if (sid->port1 == SELFID_PORT_CHILD) cldcnt[n]++;
- if (sid->port2 == SELFID_PORT_CHILD) cldcnt[n]++;
-
- speedcap[n] = sid->speed;
- if (speedcap[n] > local_link_speed)
- speedcap[n] = local_link_speed;
- n--;
- }
- }
-
- /* set self mapping */
- for (i = 0; i < nodecount; i++) {
- map[64*i + i] = speedcap[i];
- }
-
- /* fix up direct children count to total children count;
- * also fix up speedcaps for sibling and parent communication */
- for (i = 1; i < nodecount; i++) {
- for (j = cldcnt[i], n = i - 1; j > 0; j--) {
- cldcnt[i] += cldcnt[n];
- speedcap[n] = min(speedcap[n], speedcap[i]);
- n -= cldcnt[n] + 1;
- }
- }
-
- for (n = 0; n < nodecount; n++) {
- for (i = n - cldcnt[n]; i <= n; i++) {
- for (j = 0; j < (n - cldcnt[n]); j++) {
- map[j*64 + i] = map[i*64 + j] =
- min(map[i*64 + j], speedcap[n]);
- }
- for (j = n + 1; j < nodecount; j++) {
- map[j*64 + i] = map[i*64 + j] =
- min(map[i*64 + j], speedcap[n]);
- }
- }
- }
-
- /* assume a maximum speed for 1394b PHYs, nodemgr will correct it */
- if (local_link_speed > SELFID_SPEED_UNKNOWN)
- for (i = 0; i < nodecount; i++)
- if (speedcap[i] == SELFID_SPEED_UNKNOWN)
- speedcap[i] = local_link_speed;
-}
-
-
-/**
- * hpsb_selfid_received - hand over received selfid packet to the core
- *
- * For host driver module usage. Safe to use in interrupt context.
- *
- * The host driver should have done a successful complement check (second
- * quadlet is complement of first) beforehand.
- */
-void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
-{
- if (host->in_bus_reset) {
- HPSB_VERBOSE("Including SelfID 0x%x", sid);
- host->topology_map[host->selfid_count++] = sid;
- } else {
- HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",
- sid, NODEID_TO_BUS(host->node_id));
- }
-}
-
-/**
- * hpsb_selfid_complete - notify completion of SelfID stage to the core
- *
- * For host driver module usage. Safe to use in interrupt context, although
- * quite complex; so you may want to run it in the bottom rather than top half.
- *
- * Notify completion of SelfID stage to the core and report new physical ID
- * and whether host is root now.
- */
-void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
-{
- if (!host->in_bus_reset)
- HPSB_NOTICE("SelfID completion called outside of bus reset!");
-
- host->node_id = LOCAL_BUS | phyid;
- host->is_root = isroot;
-
- if (!check_selfids(host)) {
- if (host->reset_retries++ < 20) {
- /* selfid stage did not complete without error */
- HPSB_NOTICE("Error in SelfID stage, resetting");
- host->in_bus_reset = 0;
- /* this should work from ohci1394 now... */
- hpsb_reset_bus(host, LONG_RESET);
- return;
- } else {
- HPSB_NOTICE("Stopping out-of-control reset loop");
- HPSB_NOTICE("Warning - topology map and speed map will not be valid");
- host->reset_retries = 0;
- }
- } else {
- host->reset_retries = 0;
- build_speed_map(host, host->node_count);
- }
-
- HPSB_VERBOSE("selfid_complete called with successful SelfID stage "
- "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
-
- /* irm_id is kept up to date by check_selfids() */
- if (host->irm_id == host->node_id) {
- host->is_irm = 1;
- } else {
- host->is_busmgr = 0;
- host->is_irm = 0;
- }
-
- if (isroot) {
- host->driver->devctl(host, ACT_CYCLE_MASTER, 1);
- host->is_cycmst = 1;
- }
- atomic_inc(&host->generation);
- host->in_bus_reset = 0;
- highlevel_host_reset(host);
-}
-
-static DEFINE_SPINLOCK(pending_packets_lock);
-
-/**
- * hpsb_packet_sent - notify core of sending a packet
- *
- * For host driver module usage. Safe to call from within a transmit packet
- * routine.
- *
- * Notify core of sending a packet. Ackcode is the ack code returned for async
- * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
- * for other cases (internal errors that don't justify a panic).
- */
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
- int ackcode)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pending_packets_lock, flags);
-
- packet->ack_code = ackcode;
-
- if (packet->no_waiter || packet->state == hpsb_complete) {
- /* if packet->no_waiter, must not have a tlabel allocated */
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- hpsb_free_packet(packet);
- return;
- }
-
- atomic_dec(&packet->refcnt); /* drop HC's reference */
- /* here the packet must be on the host->pending_packets queue */
-
- if (ackcode != ACK_PENDING || !packet->expect_response) {
- packet->state = hpsb_complete;
- list_del_init(&packet->queue);
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- queue_packet_complete(packet);
- return;
- }
-
- packet->state = hpsb_pending;
- packet->sendtime = jiffies;
-
- spin_unlock_irqrestore(&pending_packets_lock, flags);
-
- mod_timer(&host->timeout, jiffies + host->timeout_interval);
-}
-
-/**
- * hpsb_send_phy_config - transmit a PHY configuration packet on the bus
- * @host: host that PHY config packet gets sent through
- * @rootid: root whose force_root bit should get set (-1 = don't set force_root)
- * @gapcnt: gap count value to set (-1 = don't set gap count)
- *
- * This function sends a PHY config packet on the bus through the specified
- * host.
- *
- * Return value: 0 for success or negative error number otherwise.
- */
-int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
-{
- struct hpsb_packet *packet;
- quadlet_t d = 0;
- int retval = 0;
-
- if (rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 ||
- (rootid == -1 && gapcnt == -1)) {
- HPSB_DEBUG("Invalid Parameter: rootid = %d gapcnt = %d",
- rootid, gapcnt);
- return -EINVAL;
- }
-
- if (rootid != -1)
- d |= PHYPACKET_PHYCONFIG_R | rootid << PHYPACKET_PORT_SHIFT;
- if (gapcnt != -1)
- d |= PHYPACKET_PHYCONFIG_T | gapcnt << PHYPACKET_GAPCOUNT_SHIFT;
-
- packet = hpsb_make_phypacket(host, d);
- if (!packet)
- return -ENOMEM;
-
- packet->generation = get_hpsb_generation(host);
- retval = hpsb_send_packet_and_wait(packet);
- hpsb_free_packet(packet);
-
- return retval;
-}
-
-/**
- * hpsb_send_packet - transmit a packet on the bus
- * @packet: packet to send
- *
- * The packet is sent through the host specified in the packet->host field.
- * Before sending, the packet's transmit speed is automatically determined
- * using the local speed map when it is an async, non-broadcast packet.
- *
- * Possibilities for failure are that host is either not initialized, in bus
- * reset, the packet's generation number doesn't match the current generation
- * number or the host reports a transmit error.
- *
- * Return value: 0 on success, negative errno on failure.
- */
-int hpsb_send_packet(struct hpsb_packet *packet)
-{
- struct hpsb_host *host = packet->host;
-
- if (host->is_shutdown)
- return -EINVAL;
- if (host->in_bus_reset ||
- (packet->generation != get_hpsb_generation(host)))
- return -EAGAIN;
-
- packet->state = hpsb_queued;
-
- /* This just seems silly to me */
- WARN_ON(packet->no_waiter && packet->expect_response);
-
- if (!packet->no_waiter || packet->expect_response) {
- unsigned long flags;
-
- atomic_inc(&packet->refcnt);
- /* Set the initial "sendtime" to 10 seconds from now, to
- prevent premature expiry. If a packet takes more than
- 10 seconds to hit the wire, we have bigger problems :) */
- packet->sendtime = jiffies + 10 * HZ;
- spin_lock_irqsave(&pending_packets_lock, flags);
- list_add_tail(&packet->queue, &host->pending_packets);
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- }
-
- if (packet->node_id == host->node_id) {
- /* it is a local request, so handle it locally */
-
- quadlet_t *data;
- size_t size = packet->data_size + packet->header_size;
-
- data = kmalloc(size, GFP_ATOMIC);
- if (!data) {
- HPSB_ERR("unable to allocate memory for concatenating header and data");
- return -ENOMEM;
- }
-
- memcpy(data, packet->header, packet->header_size);
-
- if (packet->data_size)
- memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size);
-
- dump_packet("send packet local", packet->header, packet->header_size, -1);
-
- hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);
- hpsb_packet_received(host, data, size, 0);
-
- kfree(data);
-
- return 0;
- }
-
- if (packet->type == hpsb_async &&
- NODEID_TO_NODE(packet->node_id) != ALL_NODES)
- packet->speed_code =
- host->speed[NODEID_TO_NODE(packet->node_id)];
-
- dump_packet("send packet", packet->header, packet->header_size, packet->speed_code);
-
- return host->driver->transmit_packet(host, packet);
-}
-
-/* We could just use complete() directly as the packet complete
- * callback, but this is more typesafe, in the sense that we get a
- * compiler error if the prototype for complete() changes. */
-
-static void complete_packet(void *data)
-{
- complete((struct completion *) data);
-}
-
-/**
- * hpsb_send_packet_and_wait - enqueue packet, block until transaction completes
- * @packet: packet to send
- *
- * Return value: 0 on success, negative errno on failure.
- */
-int hpsb_send_packet_and_wait(struct hpsb_packet *packet)
-{
- struct completion done;
- int retval;
-
- init_completion(&done);
- hpsb_set_packet_complete_task(packet, complete_packet, &done);
- retval = hpsb_send_packet(packet);
- if (retval == 0)
- wait_for_completion(&done);
-
- return retval;
-}
-
-static void send_packet_nocare(struct hpsb_packet *packet)
-{
- if (hpsb_send_packet(packet) < 0) {
- hpsb_free_packet(packet);
- }
-}
-
-static size_t packet_size_to_data_size(size_t packet_size, size_t header_size,
- size_t buffer_size, int tcode)
-{
- size_t ret = packet_size <= header_size ? 0 : packet_size - header_size;
-
- if (unlikely(ret > buffer_size))
- ret = buffer_size;
-
- if (unlikely(ret + header_size != packet_size))
- HPSB_ERR("unexpected packet size %zd (tcode %d), bug?",
- packet_size, tcode);
- return ret;
-}
-
-static void handle_packet_response(struct hpsb_host *host, int tcode,
- quadlet_t *data, size_t size)
-{
- struct hpsb_packet *packet;
- int tlabel = (data[0] >> 10) & 0x3f;
- size_t header_size;
- unsigned long flags;
-
- spin_lock_irqsave(&pending_packets_lock, flags);
-
- list_for_each_entry(packet, &host->pending_packets, queue)
- if (packet->tlabel == tlabel &&
- packet->node_id == (data[1] >> 16))
- goto found;
-
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- HPSB_DEBUG("unsolicited response packet received - %s",
- "no tlabel match");
- dump_packet("contents", data, 16, -1);
- return;
-
-found:
- switch (packet->tcode) {
- case TCODE_WRITEQ:
- case TCODE_WRITEB:
- if (unlikely(tcode != TCODE_WRITE_RESPONSE))
- break;
- header_size = 12;
- size = 0;
- goto dequeue;
-
- case TCODE_READQ:
- if (unlikely(tcode != TCODE_READQ_RESPONSE))
- break;
- header_size = 16;
- size = 0;
- goto dequeue;
-
- case TCODE_READB:
- if (unlikely(tcode != TCODE_READB_RESPONSE))
- break;
- header_size = 16;
- size = packet_size_to_data_size(size, header_size,
- packet->allocated_data_size,
- tcode);
- goto dequeue;
-
- case TCODE_LOCK_REQUEST:
- if (unlikely(tcode != TCODE_LOCK_RESPONSE))
- break;
- header_size = 16;
- size = packet_size_to_data_size(min(size, (size_t)(16 + 8)),
- header_size,
- packet->allocated_data_size,
- tcode);
- goto dequeue;
- }
-
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- HPSB_DEBUG("unsolicited response packet received - %s",
- "tcode mismatch");
- dump_packet("contents", data, 16, -1);
- return;
-
-dequeue:
- list_del_init(&packet->queue);
- spin_unlock_irqrestore(&pending_packets_lock, flags);
-
- if (packet->state == hpsb_queued) {
- packet->sendtime = jiffies;
- packet->ack_code = ACK_PENDING;
- }
- packet->state = hpsb_complete;
-
- memcpy(packet->header, data, header_size);
- if (size)
- memcpy(packet->data, data + 4, size);
-
- queue_packet_complete(packet);
-}
-
-
-static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,
- quadlet_t *data, size_t dsize)
-{
- struct hpsb_packet *p;
-
- p = hpsb_alloc_packet(dsize);
- if (unlikely(p == NULL)) {
- /* FIXME - send data_error response */
- HPSB_ERR("out of memory, cannot send response packet");
- return NULL;
- }
-
- p->type = hpsb_async;
- p->state = hpsb_unused;
- p->host = host;
- p->node_id = data[1] >> 16;
- p->tlabel = (data[0] >> 10) & 0x3f;
- p->no_waiter = 1;
-
- p->generation = get_hpsb_generation(host);
-
- if (dsize % 4)
- p->data[dsize / 4] = 0;
-
- return p;
-}
-
-#define PREP_ASYNC_HEAD_RCODE(tc) \
- packet->tcode = tc; \
- packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
- | (1 << 8) | (tc << 4); \
- packet->header[1] = (packet->host->node_id << 16) | (rcode << 12); \
- packet->header[2] = 0
-
-static void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode,
- quadlet_t data)
-{
- PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE);
- packet->header[3] = data;
- packet->header_size = 16;
- packet->data_size = 0;
-}
-
-static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
- int length)
-{
- if (rcode != RCODE_COMPLETE)
- length = 0;
-
- PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);
- packet->header[3] = length << 16;
- packet->header_size = 16;
- packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
-}
-
-static void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
-{
- PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
- packet->header_size = 12;
- packet->data_size = 0;
-}
-
-static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode,
- int length)
-{
- if (rcode != RCODE_COMPLETE)
- length = 0;
-
- PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE);
- packet->header[3] = (length << 16) | extcode;
- packet->header_size = 16;
- packet->data_size = length;
-}
-
-static void handle_incoming_packet(struct hpsb_host *host, int tcode,
- quadlet_t *data, size_t size,
- int write_acked)
-{
- struct hpsb_packet *packet;
- int length, rcode, extcode;
- quadlet_t buffer;
- nodeid_t source = data[1] >> 16;
- nodeid_t dest = data[0] >> 16;
- u16 flags = (u16) data[0];
- u64 addr;
-
- /* FIXME?
- * Out-of-bounds lengths are left for highlevel_read|write to cap. */
-
- switch (tcode) {
- case TCODE_WRITEQ:
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, source, dest, data + 3,
- addr, 4, flags);
- goto handle_write_request;
-
- case TCODE_WRITEB:
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, source, dest, data + 4,
- addr, data[3] >> 16, flags);
-handle_write_request:
- if (rcode < 0 || write_acked ||
- NODEID_TO_NODE(data[0] >> 16) == NODE_MASK)
- return;
- /* not a broadcast write, reply */
- packet = create_reply_packet(host, data, 0);
- if (packet) {
- fill_async_write_resp(packet, rcode);
- send_packet_nocare(packet);
- }
- return;
-
- case TCODE_READQ:
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
- if (rcode < 0)
- return;
-
- packet = create_reply_packet(host, data, 0);
- if (packet) {
- fill_async_readquad_resp(packet, rcode, buffer);
- send_packet_nocare(packet);
- }
- return;
-
- case TCODE_READB:
- length = data[3] >> 16;
- packet = create_reply_packet(host, data, length);
- if (!packet)
- return;
-
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, source, packet->data, addr,
- length, flags);
- if (rcode < 0) {
- hpsb_free_packet(packet);
- return;
- }
- fill_async_readblock_resp(packet, rcode, length);
- send_packet_nocare(packet);
- return;
-
- case TCODE_LOCK_REQUEST:
- length = data[3] >> 16;
- extcode = data[3] & 0xffff;
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-
- packet = create_reply_packet(host, data, 8);
- if (!packet)
- return;
-
- if (extcode == 0 || extcode >= 7) {
- /* let switch default handle error */
- length = 0;
- }
-
- switch (length) {
- case 4:
- rcode = highlevel_lock(host, source, packet->data, addr,
- data[4], 0, extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 4);
- break;
- case 8:
- if (extcode != EXTCODE_FETCH_ADD &&
- extcode != EXTCODE_LITTLE_ADD) {
- rcode = highlevel_lock(host, source,
- packet->data, addr,
- data[5], data[4],
- extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 4);
- } else {
- rcode = highlevel_lock64(host, source,
- (octlet_t *)packet->data, addr,
- *(octlet_t *)(data + 4), 0ULL,
- extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 8);
- }
- break;
- case 16:
- rcode = highlevel_lock64(host, source,
- (octlet_t *)packet->data, addr,
- *(octlet_t *)(data + 6),
- *(octlet_t *)(data + 4),
- extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 8);
- break;
- default:
- rcode = RCODE_TYPE_ERROR;
- fill_async_lock_resp(packet, rcode, extcode, 0);
- }
-
- if (rcode < 0)
- hpsb_free_packet(packet);
- else
- send_packet_nocare(packet);
- return;
- }
-}
-
-/**
- * hpsb_packet_received - hand over received packet to the core
- *
- * For host driver module usage.
- *
- * The contents of data are expected to be the full packet but with the CRCs
- * left out (data block follows header immediately), with the header (i.e. the
- * first four quadlets) in machine byte order and the data block in big endian.
- * *@data can be safely overwritten after this call.
- *
- * If the packet is a write request, @write_acked is to be set to true if it was
- * ack_complete'd already, false otherwise. This argument is ignored for any
- * other packet type.
- */
-void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
- int write_acked)
-{
- int tcode;
-
- if (unlikely(host->in_bus_reset)) {
- HPSB_DEBUG("received packet during reset; ignoring");
- return;
- }
-
- dump_packet("received packet", data, size, -1);
-
- tcode = (data[0] >> 4) & 0xf;
-
- switch (tcode) {
- case TCODE_WRITE_RESPONSE:
- case TCODE_READQ_RESPONSE:
- case TCODE_READB_RESPONSE:
- case TCODE_LOCK_RESPONSE:
- handle_packet_response(host, tcode, data, size);
- break;
-
- case TCODE_WRITEQ:
- case TCODE_WRITEB:
- case TCODE_READQ:
- case TCODE_READB:
- case TCODE_LOCK_REQUEST:
- handle_incoming_packet(host, tcode, data, size, write_acked);
- break;
-
- case TCODE_CYCLE_START:
- /* simply ignore this packet if it is passed on */
- break;
-
- default:
- HPSB_DEBUG("received packet with bogus transaction code %d",
- tcode);
- break;
- }
-}
-
-static void abort_requests(struct hpsb_host *host)
-{
- struct hpsb_packet *packet, *p;
- struct list_head tmp;
- unsigned long flags;
-
- host->driver->devctl(host, CANCEL_REQUESTS, 0);
-
- INIT_LIST_HEAD(&tmp);
- spin_lock_irqsave(&pending_packets_lock, flags);
- list_splice_init(&host->pending_packets, &tmp);
- spin_unlock_irqrestore(&pending_packets_lock, flags);
-
- list_for_each_entry_safe(packet, p, &tmp, queue) {
- list_del_init(&packet->queue);
- packet->state = hpsb_complete;
- packet->ack_code = ACKX_ABORTED;
- queue_packet_complete(packet);
- }
-}
-
-void abort_timedouts(unsigned long __opaque)
-{
- struct hpsb_host *host = (struct hpsb_host *)__opaque;
- struct hpsb_packet *packet, *p;
- struct list_head tmp;
- unsigned long flags, expire, j;
-
- spin_lock_irqsave(&host->csr.lock, flags);
- expire = host->csr.expire;
- spin_unlock_irqrestore(&host->csr.lock, flags);
-
- j = jiffies;
- INIT_LIST_HEAD(&tmp);
- spin_lock_irqsave(&pending_packets_lock, flags);
-
- list_for_each_entry_safe(packet, p, &host->pending_packets, queue) {
- if (time_before(packet->sendtime + expire, j))
- list_move_tail(&packet->queue, &tmp);
- else
- /* Since packets are added to the tail, the oldest
- * ones are first, always. When we get to one that
- * isn't timed out, the rest aren't either. */
- break;
- }
- if (!list_empty(&host->pending_packets))
- mod_timer(&host->timeout, j + host->timeout_interval);
-
- spin_unlock_irqrestore(&pending_packets_lock, flags);
-
- list_for_each_entry_safe(packet, p, &tmp, queue) {
- list_del_init(&packet->queue);
- packet->state = hpsb_complete;
- packet->ack_code = ACKX_TIMEOUT;
- queue_packet_complete(packet);
- }
-}
-
-static struct task_struct *khpsbpkt_thread;
-static LIST_HEAD(hpsbpkt_queue);
-
-static void queue_packet_complete(struct hpsb_packet *packet)
-{
- unsigned long flags;
-
- if (packet->no_waiter) {
- hpsb_free_packet(packet);
- return;
- }
- if (packet->complete_routine != NULL) {
- spin_lock_irqsave(&pending_packets_lock, flags);
- list_add_tail(&packet->queue, &hpsbpkt_queue);
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- wake_up_process(khpsbpkt_thread);
- }
- return;
-}
-
-/*
- * Kernel thread which handles packets that are completed. This way the
- * packet's "complete" function is asynchronously run in process context.
- * Only packets which have a "complete" function may be sent here.
- */
-static int hpsbpkt_thread(void *__hi)
-{
- struct hpsb_packet *packet, *p;
- struct list_head tmp;
- int may_schedule;
-
- while (!kthread_should_stop()) {
-
- INIT_LIST_HEAD(&tmp);
- spin_lock_irq(&pending_packets_lock);
- list_splice_init(&hpsbpkt_queue, &tmp);
- spin_unlock_irq(&pending_packets_lock);
-
- list_for_each_entry_safe(packet, p, &tmp, queue) {
- list_del_init(&packet->queue);
- packet->complete_routine(packet->complete_data);
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irq(&pending_packets_lock);
- may_schedule = list_empty(&hpsbpkt_queue);
- spin_unlock_irq(&pending_packets_lock);
- if (may_schedule)
- schedule();
- __set_current_state(TASK_RUNNING);
- }
- return 0;
-}
-
-static int __init ieee1394_init(void)
-{
- int i, ret;
-
- /* non-fatal error */
- if (hpsb_init_config_roms()) {
- HPSB_ERR("Failed to initialize some config rom entries.\n");
- HPSB_ERR("Some features may not be available\n");
- }
-
- khpsbpkt_thread = kthread_run(hpsbpkt_thread, NULL, "khpsbpkt");
- if (IS_ERR(khpsbpkt_thread)) {
- HPSB_ERR("Failed to start hpsbpkt thread!\n");
- ret = PTR_ERR(khpsbpkt_thread);
- goto exit_cleanup_config_roms;
- }
-
- if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) {
- HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
- ret = -ENODEV;
- goto exit_release_kernel_thread;
- }
-
- ret = bus_register(&ieee1394_bus_type);
- if (ret < 0) {
- HPSB_INFO("bus register failed");
- goto release_chrdev;
- }
-
- for (i = 0; fw_bus_attrs[i]; i++) {
- ret = bus_create_file(&ieee1394_bus_type, fw_bus_attrs[i]);
- if (ret < 0) {
- while (i >= 0) {
- bus_remove_file(&ieee1394_bus_type,
- fw_bus_attrs[i--]);
- }
- bus_unregister(&ieee1394_bus_type);
- goto release_chrdev;
- }
- }
-
- ret = class_register(&hpsb_host_class);
- if (ret < 0)
- goto release_all_bus;
-
- hpsb_protocol_class = class_create(THIS_MODULE, "ieee1394_protocol");
- if (IS_ERR(hpsb_protocol_class)) {
- ret = PTR_ERR(hpsb_protocol_class);
- goto release_class_host;
- }
-
- ret = init_csr();
- if (ret) {
- HPSB_INFO("init csr failed");
- ret = -ENOMEM;
- goto release_class_protocol;
- }
-
- if (disable_nodemgr) {
- HPSB_INFO("nodemgr and IRM functionality disabled");
- /* We shouldn't contend for IRM with nodemgr disabled, since
- nodemgr implements functionality required of ieee1394a-2000
- IRMs */
- hpsb_disable_irm = 1;
-
- return 0;
- }
-
- if (hpsb_disable_irm) {
- HPSB_INFO("IRM functionality disabled");
- }
-
- ret = init_ieee1394_nodemgr();
- if (ret < 0) {
- HPSB_INFO("init nodemgr failed");
- goto cleanup_csr;
- }
-
- return 0;
-
-cleanup_csr:
- cleanup_csr();
-release_class_protocol:
- class_destroy(hpsb_protocol_class);
-release_class_host:
- class_unregister(&hpsb_host_class);
-release_all_bus:
- for (i = 0; fw_bus_attrs[i]; i++)
- bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
- bus_unregister(&ieee1394_bus_type);
-release_chrdev:
- unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
-exit_release_kernel_thread:
- kthread_stop(khpsbpkt_thread);
-exit_cleanup_config_roms:
- hpsb_cleanup_config_roms();
- return ret;
-}
-
-static void __exit ieee1394_cleanup(void)
-{
- int i;
-
- if (!disable_nodemgr)
- cleanup_ieee1394_nodemgr();
-
- cleanup_csr();
-
- class_destroy(hpsb_protocol_class);
- class_unregister(&hpsb_host_class);
- for (i = 0; fw_bus_attrs[i]; i++)
- bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
- bus_unregister(&ieee1394_bus_type);
-
- kthread_stop(khpsbpkt_thread);
-
- hpsb_cleanup_config_roms();
-
- unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
-}
-
-fs_initcall(ieee1394_init);
-module_exit(ieee1394_cleanup);
-
-/* Exported symbols */
-
-/** hosts.c **/
-EXPORT_SYMBOL(hpsb_alloc_host);
-EXPORT_SYMBOL(hpsb_add_host);
-EXPORT_SYMBOL(hpsb_resume_host);
-EXPORT_SYMBOL(hpsb_remove_host);
-EXPORT_SYMBOL(hpsb_update_config_rom_image);
-
-/** ieee1394_core.c **/
-EXPORT_SYMBOL(hpsb_speedto_str);
-EXPORT_SYMBOL(hpsb_protocol_class);
-EXPORT_SYMBOL(hpsb_set_packet_complete_task);
-EXPORT_SYMBOL(hpsb_alloc_packet);
-EXPORT_SYMBOL(hpsb_free_packet);
-EXPORT_SYMBOL(hpsb_send_packet);
-EXPORT_SYMBOL(hpsb_reset_bus);
-EXPORT_SYMBOL(hpsb_read_cycle_timer);
-EXPORT_SYMBOL(hpsb_bus_reset);
-EXPORT_SYMBOL(hpsb_selfid_received);
-EXPORT_SYMBOL(hpsb_selfid_complete);
-EXPORT_SYMBOL(hpsb_packet_sent);
-EXPORT_SYMBOL(hpsb_packet_received);
-EXPORT_SYMBOL_GPL(hpsb_disable_irm);
-
-/** ieee1394_transactions.c **/
-EXPORT_SYMBOL(hpsb_get_tlabel);
-EXPORT_SYMBOL(hpsb_free_tlabel);
-EXPORT_SYMBOL(hpsb_make_readpacket);
-EXPORT_SYMBOL(hpsb_make_writepacket);
-EXPORT_SYMBOL(hpsb_make_streampacket);
-EXPORT_SYMBOL(hpsb_make_lockpacket);
-EXPORT_SYMBOL(hpsb_make_lock64packet);
-EXPORT_SYMBOL(hpsb_make_phypacket);
-EXPORT_SYMBOL(hpsb_read);
-EXPORT_SYMBOL(hpsb_write);
-EXPORT_SYMBOL(hpsb_lock);
-EXPORT_SYMBOL(hpsb_packet_success);
-
-/** highlevel.c **/
-EXPORT_SYMBOL(hpsb_register_highlevel);
-EXPORT_SYMBOL(hpsb_unregister_highlevel);
-EXPORT_SYMBOL(hpsb_register_addrspace);
-EXPORT_SYMBOL(hpsb_unregister_addrspace);
-EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace);
-EXPORT_SYMBOL(hpsb_get_hostinfo);
-EXPORT_SYMBOL(hpsb_create_hostinfo);
-EXPORT_SYMBOL(hpsb_destroy_hostinfo);
-EXPORT_SYMBOL(hpsb_set_hostinfo_key);
-EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
-EXPORT_SYMBOL(hpsb_set_hostinfo);
-
-/** nodemgr.c **/
-EXPORT_SYMBOL(hpsb_node_fill_packet);
-EXPORT_SYMBOL(hpsb_node_write);
-EXPORT_SYMBOL(__hpsb_register_protocol);
-EXPORT_SYMBOL(hpsb_unregister_protocol);
-
-/** csr.c **/
-EXPORT_SYMBOL(hpsb_update_config_rom);
-
-/** dma.c **/
-EXPORT_SYMBOL(dma_prog_region_init);
-EXPORT_SYMBOL(dma_prog_region_alloc);
-EXPORT_SYMBOL(dma_prog_region_free);
-EXPORT_SYMBOL(dma_region_init);
-EXPORT_SYMBOL(dma_region_alloc);
-EXPORT_SYMBOL(dma_region_free);
-EXPORT_SYMBOL(dma_region_sync_for_cpu);
-EXPORT_SYMBOL(dma_region_sync_for_device);
-EXPORT_SYMBOL(dma_region_mmap);
-EXPORT_SYMBOL(dma_region_offset_to_bus);
-
-/** iso.c **/
-EXPORT_SYMBOL(hpsb_iso_xmit_init);
-EXPORT_SYMBOL(hpsb_iso_recv_init);
-EXPORT_SYMBOL(hpsb_iso_xmit_start);
-EXPORT_SYMBOL(hpsb_iso_recv_start);
-EXPORT_SYMBOL(hpsb_iso_recv_listen_channel);
-EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel);
-EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask);
-EXPORT_SYMBOL(hpsb_iso_stop);
-EXPORT_SYMBOL(hpsb_iso_shutdown);
-EXPORT_SYMBOL(hpsb_iso_xmit_queue_packet);
-EXPORT_SYMBOL(hpsb_iso_xmit_sync);
-EXPORT_SYMBOL(hpsb_iso_recv_release_packets);
-EXPORT_SYMBOL(hpsb_iso_n_ready);
-EXPORT_SYMBOL(hpsb_iso_packet_sent);
-EXPORT_SYMBOL(hpsb_iso_packet_received);
-EXPORT_SYMBOL(hpsb_iso_wake);
-EXPORT_SYMBOL(hpsb_iso_recv_flush);
-
-/** csr1212.c **/
-EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
-EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
-EXPORT_SYMBOL(csr1212_get_keyval);
-EXPORT_SYMBOL(csr1212_new_directory);
-EXPORT_SYMBOL(csr1212_parse_keyval);
-EXPORT_SYMBOL(csr1212_read);
-EXPORT_SYMBOL(csr1212_release_keyval);
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
deleted file mode 100644
index 28b9f58bafd2..000000000000
--- a/drivers/ieee1394/ieee1394_core.h
+++ /dev/null
@@ -1,172 +0,0 @@
-#ifndef _IEEE1394_CORE_H
-#define _IEEE1394_CORE_H
-
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/cdev.h>
-#include <asm/atomic.h>
-
-#include "hosts.h"
-#include "ieee1394_types.h"
-
-struct hpsb_packet {
- /* This struct is basically read-only for hosts with the exception of
- * the data buffer contents and driver_list. */
-
- /* This can be used for host driver internal linking.
- *
- * NOTE: This must be left in init state when the driver is done
- * with it (e.g. by using list_del_init()), since the core does
- * some sanity checks to make sure the packet is not on a
- * driver_list when free'ing it. */
- struct list_head driver_list;
-
- nodeid_t node_id;
-
- /* hpsb_raw = send as-is, do not CRC (but still byte-swap it) */
- enum { hpsb_async, hpsb_raw } __attribute__((packed)) type;
-
- /* Okay, this is core internal and a no care for hosts.
- * queued = queued for sending
- * pending = sent, waiting for response
- * complete = processing completed, successful or not
- */
- enum {
- hpsb_unused, hpsb_queued, hpsb_pending, hpsb_complete
- } __attribute__((packed)) state;
-
- /* These are core-internal. */
- signed char tlabel;
- signed char ack_code;
- unsigned char tcode;
-
- unsigned expect_response:1;
- unsigned no_waiter:1;
-
- /* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
- unsigned speed_code:2;
-
- struct hpsb_host *host;
- unsigned int generation;
-
- atomic_t refcnt;
- struct list_head queue;
-
- /* Function (and possible data to pass to it) to call when this
- * packet is completed. */
- void (*complete_routine)(void *);
- void *complete_data;
-
- /* Store jiffies for implementing bus timeouts. */
- unsigned long sendtime;
-
- /* Core-internal. */
- size_t allocated_data_size; /* as allocated */
-
- /* Sizes are in bytes. To be set by caller of hpsb_alloc_packet. */
- size_t data_size; /* as filled in */
- size_t header_size; /* as filled in, not counting the CRC */
-
- /* Buffers */
- quadlet_t *data; /* can be DMA-mapped */
- quadlet_t header[5];
- quadlet_t embedded_data[0]; /* keep as last member */
-};
-
-void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
- void (*routine)(void *), void *data);
-static inline struct hpsb_packet *driver_packet(struct list_head *l)
-{
- return list_entry(l, struct hpsb_packet, driver_list);
-}
-void abort_timedouts(unsigned long __opaque);
-struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
-void hpsb_free_packet(struct hpsb_packet *packet);
-
-/**
- * get_hpsb_generation - generation counter for the complete 1394 subsystem
- *
- * Generation gets incremented on every change in the subsystem (notably on bus
- * resets). Use the functions, not the variable.
- */
-static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
-{
- return atomic_read(&host->generation);
-}
-
-int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
-int hpsb_send_packet(struct hpsb_packet *packet);
-int hpsb_send_packet_and_wait(struct hpsb_packet *packet);
-int hpsb_reset_bus(struct hpsb_host *host, int type);
-int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
- u64 *local_time);
-
-int hpsb_bus_reset(struct hpsb_host *host);
-void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
-void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
- int ackcode);
-void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
- int write_acked);
-
-/*
- * CHARACTER DEVICE DISPATCHING
- *
- * All ieee1394 character device drivers share the same major number
- * (major 171). The 256 minor numbers are allocated to the various
- * task-specific interfaces (raw1394, video1394, dv1394, etc) in
- * blocks of 16.
- *
- * The core ieee1394.o module allocates the device number region
- * 171:0-255, the various drivers must then cdev_add() their cdev
- * objects to handle their respective sub-regions.
- *
- * Minor device number block allocations:
- *
- * Block 0 ( 0- 15) raw1394
- * Block 1 ( 16- 31) video1394
- * Block 2 ( 32- 47) dv1394
- *
- * Blocks 3-14 free for future allocation
- *
- * Block 15 (240-255) reserved for drivers under development, etc.
- */
-
-#define IEEE1394_MAJOR 171
-
-#define IEEE1394_MINOR_BLOCK_RAW1394 0
-#define IEEE1394_MINOR_BLOCK_VIDEO1394 1
-#define IEEE1394_MINOR_BLOCK_DV1394 2
-#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
-
-#define IEEE1394_CORE_DEV MKDEV(IEEE1394_MAJOR, 0)
-#define IEEE1394_RAW1394_DEV MKDEV(IEEE1394_MAJOR, \
- IEEE1394_MINOR_BLOCK_RAW1394 * 16)
-#define IEEE1394_VIDEO1394_DEV MKDEV(IEEE1394_MAJOR, \
- IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
-#define IEEE1394_DV1394_DEV MKDEV(IEEE1394_MAJOR, \
- IEEE1394_MINOR_BLOCK_DV1394 * 16)
-#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
- IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
-
-/**
- * ieee1394_file_to_instance - get the index within a minor number block
- */
-static inline unsigned char ieee1394_file_to_instance(struct file *file)
-{
- int idx = cdev_index(file->f_path.dentry->d_inode);
- if (idx < 0)
- idx = 0;
- return idx;
-}
-
-extern int hpsb_disable_irm;
-
-/* Our sysfs bus entry */
-extern struct bus_type ieee1394_bus_type;
-extern struct class hpsb_host_class;
-extern struct class *hpsb_protocol_class;
-
-#endif /* _IEEE1394_CORE_H */
diff --git a/drivers/ieee1394/ieee1394_hotplug.h b/drivers/ieee1394/ieee1394_hotplug.h
deleted file mode 100644
index dd5500ed8322..000000000000
--- a/drivers/ieee1394/ieee1394_hotplug.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _IEEE1394_HOTPLUG_H
-#define _IEEE1394_HOTPLUG_H
-
-/* Unit spec id and sw version entry for some protocols */
-#define AVC_UNIT_SPEC_ID_ENTRY 0x0000A02D
-#define AVC_SW_VERSION_ENTRY 0x00010001
-#define CAMERA_UNIT_SPEC_ID_ENTRY 0x0000A02D
-#define CAMERA_SW_VERSION_ENTRY 0x00000100
-
-/* /include/linux/mod_devicetable.h defines:
- * IEEE1394_MATCH_VENDOR_ID
- * IEEE1394_MATCH_MODEL_ID
- * IEEE1394_MATCH_SPECIFIER_ID
- * IEEE1394_MATCH_VERSION
- * struct ieee1394_device_id
- */
-#include <linux/mod_devicetable.h>
-
-#endif /* _IEEE1394_HOTPLUG_H */
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
deleted file mode 100644
index 675b3135d5f1..000000000000
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Transaction support.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/bitops.h>
-#include <linux/compiler.h>
-#include <linux/hardirq.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/sched.h> /* because linux/wait.h is broken if CONFIG_SMP=n */
-#include <linux/wait.h>
-
-#include <asm/bug.h>
-#include <asm/errno.h>
-#include <asm/system.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "ieee1394_transactions.h"
-
-#define PREP_ASYNC_HEAD_ADDRESS(tc) \
- packet->tcode = tc; \
- packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
- | (1 << 8) | (tc << 4); \
- packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
- packet->header[2] = addr & 0xffffffff
-
-#ifndef HPSB_DEBUG_TLABELS
-static
-#endif
-DEFINE_SPINLOCK(hpsb_tlabel_lock);
-
-static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
-
-static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
-{
- PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
- packet->header_size = 12;
- packet->data_size = 0;
- packet->expect_response = 1;
-}
-
-static void fill_async_readblock(struct hpsb_packet *packet, u64 addr,
- int length)
-{
- PREP_ASYNC_HEAD_ADDRESS(TCODE_READB);
- packet->header[3] = length << 16;
- packet->header_size = 16;
- packet->data_size = 0;
- packet->expect_response = 1;
-}
-
-static void fill_async_writequad(struct hpsb_packet *packet, u64 addr,
- quadlet_t data)
-{
- PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ);
- packet->header[3] = data;
- packet->header_size = 16;
- packet->data_size = 0;
- packet->expect_response = 1;
-}
-
-static void fill_async_writeblock(struct hpsb_packet *packet, u64 addr,
- int length)
-{
- PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
- packet->header[3] = length << 16;
- packet->header_size = 16;
- packet->expect_response = 1;
- packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
-}
-
-static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
- int length)
-{
- PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST);
- packet->header[3] = (length << 16) | extcode;
- packet->header_size = 16;
- packet->data_size = length;
- packet->expect_response = 1;
-}
-
-static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
-{
- packet->header[0] = data;
- packet->header[1] = ~data;
- packet->header_size = 8;
- packet->data_size = 0;
- packet->expect_response = 0;
- packet->type = hpsb_raw; /* No CRC added */
- packet->speed_code = IEEE1394_SPEED_100; /* Force speed to be 100Mbps */
-}
-
-static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
- int channel, int tag, int sync)
-{
- packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
- | (TCODE_STREAM_DATA << 4) | sync;
-
- packet->header_size = 4;
- packet->data_size = length;
- packet->type = hpsb_async;
- packet->tcode = TCODE_ISO_DATA;
-}
-
-/* same as hpsb_get_tlabel, except that it returns immediately */
-static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
-{
- unsigned long flags, *tp;
- u8 *next;
- int tlabel, n = NODEID_TO_NODE(packet->node_id);
-
- /* Broadcast transactions are complete once the request has been sent.
- * Use the same transaction label for all broadcast transactions. */
- if (unlikely(n == ALL_NODES)) {
- packet->tlabel = 0;
- return 0;
- }
- tp = packet->host->tl_pool[n].map;
- next = &packet->host->next_tl[n];
-
- spin_lock_irqsave(&hpsb_tlabel_lock, flags);
- tlabel = find_next_zero_bit(tp, 64, *next);
- if (tlabel > 63)
- tlabel = find_first_zero_bit(tp, 64);
- if (tlabel > 63) {
- spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
- return -EAGAIN;
- }
- __set_bit(tlabel, tp);
- *next = (tlabel + 1) & 63;
- spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
- packet->tlabel = tlabel;
- return 0;
-}
-
-/**
- * hpsb_get_tlabel - allocate a transaction label
- * @packet: the packet whose tlabel and tl_pool we set
- *
- * Every asynchronous transaction on the 1394 bus needs a transaction
- * label to match the response to the request. This label has to be
- * different from any other transaction label in an outstanding request to
- * the same node to make matching possible without ambiguity.
- *
- * There are 64 different tlabels, so an allocated tlabel has to be freed
- * with hpsb_free_tlabel() after the transaction is complete (unless it's
- * reused again for the same target node).
- *
- * Return value: Zero on success, otherwise non-zero. A non-zero return
- * generally means there are no available tlabels. If this is called out
- * of interrupt or atomic context, then it will sleep until can return a
- * tlabel or a signal is received.
- */
-int hpsb_get_tlabel(struct hpsb_packet *packet)
-{
- if (irqs_disabled() || in_atomic())
- return hpsb_get_tlabel_atomic(packet);
-
- /* NB: The macro wait_event_interruptible() is called with a condition
- * argument with side effect. This is only possible because the side
- * effect does not occur until the condition became true, and
- * wait_event_interruptible() won't evaluate the condition again after
- * that. */
- return wait_event_interruptible(tlabel_wq,
- !hpsb_get_tlabel_atomic(packet));
-}
-
-/**
- * hpsb_free_tlabel - free an allocated transaction label
- * @packet: packet whose tlabel and tl_pool needs to be cleared
- *
- * Frees the transaction label allocated with hpsb_get_tlabel(). The
- * tlabel has to be freed after the transaction is complete (i.e. response
- * was received for a split transaction or packet was sent for a unified
- * transaction).
- *
- * A tlabel must not be freed twice.
- */
-void hpsb_free_tlabel(struct hpsb_packet *packet)
-{
- unsigned long flags, *tp;
- int tlabel, n = NODEID_TO_NODE(packet->node_id);
-
- if (unlikely(n == ALL_NODES))
- return;
- tp = packet->host->tl_pool[n].map;
- tlabel = packet->tlabel;
- BUG_ON(tlabel > 63 || tlabel < 0);
-
- spin_lock_irqsave(&hpsb_tlabel_lock, flags);
- BUG_ON(!__test_and_clear_bit(tlabel, tp));
- spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
- wake_up_interruptible(&tlabel_wq);
-}
-
-/**
- * hpsb_packet_success - Make sense of the ack and reply codes
- *
- * Make sense of the ack and reply codes and return more convenient error codes:
- * 0 = success. -%EBUSY = node is busy, try again. -%EAGAIN = error which can
- * probably resolved by retry. -%EREMOTEIO = node suffers from an internal
- * error. -%EACCES = this transaction is not allowed on requested address.
- * -%EINVAL = invalid address at node.
- */
-int hpsb_packet_success(struct hpsb_packet *packet)
-{
- switch (packet->ack_code) {
- case ACK_PENDING:
- switch ((packet->header[1] >> 12) & 0xf) {
- case RCODE_COMPLETE:
- return 0;
- case RCODE_CONFLICT_ERROR:
- return -EAGAIN;
- case RCODE_DATA_ERROR:
- return -EREMOTEIO;
- case RCODE_TYPE_ERROR:
- return -EACCES;
- case RCODE_ADDRESS_ERROR:
- return -EINVAL;
- default:
- HPSB_ERR("received reserved rcode %d from node %d",
- (packet->header[1] >> 12) & 0xf,
- packet->node_id);
- return -EAGAIN;
- }
-
- case ACK_BUSY_X:
- case ACK_BUSY_A:
- case ACK_BUSY_B:
- return -EBUSY;
-
- case ACK_TYPE_ERROR:
- return -EACCES;
-
- case ACK_COMPLETE:
- if (packet->tcode == TCODE_WRITEQ
- || packet->tcode == TCODE_WRITEB) {
- return 0;
- } else {
- HPSB_ERR("impossible ack_complete from node %d "
- "(tcode %d)", packet->node_id, packet->tcode);
- return -EAGAIN;
- }
-
- case ACK_DATA_ERROR:
- if (packet->tcode == TCODE_WRITEB
- || packet->tcode == TCODE_LOCK_REQUEST) {
- return -EAGAIN;
- } else {
- HPSB_ERR("impossible ack_data_error from node %d "
- "(tcode %d)", packet->node_id, packet->tcode);
- return -EAGAIN;
- }
-
- case ACK_ADDRESS_ERROR:
- return -EINVAL;
-
- case ACK_TARDY:
- case ACK_CONFLICT_ERROR:
- case ACKX_NONE:
- case ACKX_SEND_ERROR:
- case ACKX_ABORTED:
- case ACKX_TIMEOUT:
- /* error while sending */
- return -EAGAIN;
-
- default:
- HPSB_ERR("got invalid ack %d from node %d (tcode %d)",
- packet->ack_code, packet->node_id, packet->tcode);
- return -EAGAIN;
- }
-}
-
-struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, size_t length)
-{
- struct hpsb_packet *packet;
-
- if (length == 0)
- return NULL;
-
- packet = hpsb_alloc_packet(length);
- if (!packet)
- return NULL;
-
- packet->host = host;
- packet->node_id = node;
-
- if (hpsb_get_tlabel(packet)) {
- hpsb_free_packet(packet);
- return NULL;
- }
-
- if (length == 4)
- fill_async_readquad(packet, addr);
- else
- fill_async_readblock(packet, addr, length);
-
- return packet;
-}
-
-struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, quadlet_t * buffer,
- size_t length)
-{
- struct hpsb_packet *packet;
-
- if (length == 0)
- return NULL;
-
- packet = hpsb_alloc_packet(length);
- if (!packet)
- return NULL;
-
- if (length % 4) { /* zero padding bytes */
- packet->data[length >> 2] = 0;
- }
- packet->host = host;
- packet->node_id = node;
-
- if (hpsb_get_tlabel(packet)) {
- hpsb_free_packet(packet);
- return NULL;
- }
-
- if (length == 4) {
- fill_async_writequad(packet, addr, buffer ? *buffer : 0);
- } else {
- fill_async_writeblock(packet, addr, length);
- if (buffer)
- memcpy(packet->data, buffer, length);
- }
-
- return packet;
-}
-
-struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer,
- int length, int channel, int tag,
- int sync)
-{
- struct hpsb_packet *packet;
-
- if (length == 0)
- return NULL;
-
- packet = hpsb_alloc_packet(length);
- if (!packet)
- return NULL;
-
- if (length % 4) { /* zero padding bytes */
- packet->data[length >> 2] = 0;
- }
- packet->host = host;
-
- /* Because it is too difficult to determine all PHY speeds and link
- * speeds here, we use S100... */
- packet->speed_code = IEEE1394_SPEED_100;
-
- /* ...and prevent hpsb_send_packet() from overriding it. */
- packet->node_id = LOCAL_BUS | ALL_NODES;
-
- if (hpsb_get_tlabel(packet)) {
- hpsb_free_packet(packet);
- return NULL;
- }
-
- fill_async_stream_packet(packet, length, channel, tag, sync);
- if (buffer)
- memcpy(packet->data, buffer, length);
-
- return packet;
-}
-
-struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, int extcode,
- quadlet_t * data, quadlet_t arg)
-{
- struct hpsb_packet *p;
- u32 length;
-
- p = hpsb_alloc_packet(8);
- if (!p)
- return NULL;
-
- p->host = host;
- p->node_id = node;
- if (hpsb_get_tlabel(p)) {
- hpsb_free_packet(p);
- return NULL;
- }
-
- switch (extcode) {
- case EXTCODE_FETCH_ADD:
- case EXTCODE_LITTLE_ADD:
- length = 4;
- if (data)
- p->data[0] = *data;
- break;
- default:
- length = 8;
- if (data) {
- p->data[0] = arg;
- p->data[1] = *data;
- }
- break;
- }
- fill_async_lock(p, addr, extcode, length);
-
- return p;
-}
-
-struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
- nodeid_t node, u64 addr, int extcode,
- octlet_t * data, octlet_t arg)
-{
- struct hpsb_packet *p;
- u32 length;
-
- p = hpsb_alloc_packet(16);
- if (!p)
- return NULL;
-
- p->host = host;
- p->node_id = node;
- if (hpsb_get_tlabel(p)) {
- hpsb_free_packet(p);
- return NULL;
- }
-
- switch (extcode) {
- case EXTCODE_FETCH_ADD:
- case EXTCODE_LITTLE_ADD:
- length = 8;
- if (data) {
- p->data[0] = *data >> 32;
- p->data[1] = *data & 0xffffffff;
- }
- break;
- default:
- length = 16;
- if (data) {
- p->data[0] = arg >> 32;
- p->data[1] = arg & 0xffffffff;
- p->data[2] = *data >> 32;
- p->data[3] = *data & 0xffffffff;
- }
- break;
- }
- fill_async_lock(p, addr, extcode, length);
-
- return p;
-}
-
-struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data)
-{
- struct hpsb_packet *p;
-
- p = hpsb_alloc_packet(0);
- if (!p)
- return NULL;
-
- p->host = host;
- fill_phy_packet(p, data);
-
- return p;
-}
-
-/*
- * FIXME - these functions should probably read from / write to user space to
- * avoid in kernel buffers for user space callers
- */
-
-/**
- * hpsb_read - generic read function
- *
- * Recognizes the local node ID and act accordingly. Automatically uses a
- * quadlet read request if @length == 4 and and a block read request otherwise.
- * It does not yet support lengths that are not a multiple of 4.
- *
- * You must explicitly specifiy the @generation for which the node ID is valid,
- * to avoid sending packets to the wrong nodes when we race with a bus reset.
- */
-int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, quadlet_t * buffer, size_t length)
-{
- struct hpsb_packet *packet;
- int retval = 0;
-
- if (length == 0)
- return -EINVAL;
-
- packet = hpsb_make_readpacket(host, node, addr, length);
-
- if (!packet) {
- return -ENOMEM;
- }
-
- packet->generation = generation;
- retval = hpsb_send_packet_and_wait(packet);
- if (retval < 0)
- goto hpsb_read_fail;
-
- retval = hpsb_packet_success(packet);
-
- if (retval == 0) {
- if (length == 4) {
- *buffer = packet->header[3];
- } else {
- memcpy(buffer, packet->data, length);
- }
- }
-
- hpsb_read_fail:
- hpsb_free_tlabel(packet);
- hpsb_free_packet(packet);
-
- return retval;
-}
-
-/**
- * hpsb_write - generic write function
- *
- * Recognizes the local node ID and act accordingly. Automatically uses a
- * quadlet write request if @length == 4 and and a block write request
- * otherwise. It does not yet support lengths that are not a multiple of 4.
- *
- * You must explicitly specifiy the @generation for which the node ID is valid,
- * to avoid sending packets to the wrong nodes when we race with a bus reset.
- */
-int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, quadlet_t * buffer, size_t length)
-{
- struct hpsb_packet *packet;
- int retval;
-
- if (length == 0)
- return -EINVAL;
-
- packet = hpsb_make_writepacket(host, node, addr, buffer, length);
-
- if (!packet)
- return -ENOMEM;
-
- packet->generation = generation;
- retval = hpsb_send_packet_and_wait(packet);
- if (retval < 0)
- goto hpsb_write_fail;
-
- retval = hpsb_packet_success(packet);
-
- hpsb_write_fail:
- hpsb_free_tlabel(packet);
- hpsb_free_packet(packet);
-
- return retval;
-}
-
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
-{
- struct hpsb_packet *packet;
- int retval = 0;
-
- packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
- if (!packet)
- return -ENOMEM;
-
- packet->generation = generation;
- retval = hpsb_send_packet_and_wait(packet);
- if (retval < 0)
- goto hpsb_lock_fail;
-
- retval = hpsb_packet_success(packet);
-
- if (retval == 0)
- *data = packet->data[0];
-
-hpsb_lock_fail:
- hpsb_free_tlabel(packet);
- hpsb_free_packet(packet);
-
- return retval;
-}
diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
deleted file mode 100644
index 20b693be14b2..000000000000
--- a/drivers/ieee1394/ieee1394_transactions.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _IEEE1394_TRANSACTIONS_H
-#define _IEEE1394_TRANSACTIONS_H
-
-#include <linux/types.h>
-
-#include "ieee1394_types.h"
-
-struct hpsb_packet;
-struct hpsb_host;
-
-int hpsb_get_tlabel(struct hpsb_packet *packet);
-void hpsb_free_tlabel(struct hpsb_packet *packet);
-struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, size_t length);
-struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, int extcode, quadlet_t *data,
- quadlet_t arg);
-struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
- nodeid_t node, u64 addr, int extcode,
- octlet_t *data, octlet_t arg);
-struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data);
-struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
- nodeid_t node, u64 addr,
- quadlet_t *buffer, size_t length);
-struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
- int length, int channel, int tag,
- int sync);
-int hpsb_packet_success(struct hpsb_packet *packet);
-int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, quadlet_t *buffer, size_t length);
-int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, quadlet_t *buffer, size_t length);
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
-
-#ifdef HPSB_DEBUG_TLABELS
-extern spinlock_t hpsb_tlabel_lock;
-#endif
-
-#endif /* _IEEE1394_TRANSACTIONS_H */
diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
deleted file mode 100644
index 9803aaa15be0..000000000000
--- a/drivers/ieee1394/ieee1394_types.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef _IEEE1394_TYPES_H
-#define _IEEE1394_TYPES_H
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-typedef u32 quadlet_t;
-typedef u64 octlet_t;
-typedef u16 nodeid_t;
-
-typedef u8 byte_t;
-typedef u64 nodeaddr_t;
-typedef u16 arm_length_t;
-
-#define BUS_MASK 0xffc0
-#define BUS_SHIFT 6
-#define NODE_MASK 0x003f
-#define LOCAL_BUS 0xffc0
-#define ALL_NODES 0x003f
-
-#define NODEID_TO_BUS(nodeid) ((nodeid & BUS_MASK) >> BUS_SHIFT)
-#define NODEID_TO_NODE(nodeid) (nodeid & NODE_MASK)
-
-/* Can be used to consistently print a node/bus ID. */
-#define NODE_BUS_FMT "%d-%02d:%04d"
-#define NODE_BUS_ARGS(__host, __nodeid) \
- __host->id, NODEID_TO_NODE(__nodeid), NODEID_TO_BUS(__nodeid)
-
-#define HPSB_PRINT(level, fmt, args...) \
- printk(level "ieee1394: " fmt "\n" , ## args)
-
-#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
-#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args)
-#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args)
-#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args)
-#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
-#define HPSB_DEBUG_TLABELS
-#else
-#define HPSB_VERBOSE(fmt, args...) do {} while (0)
-#endif
-
-#ifdef __BIG_ENDIAN
-
-static inline void *memcpy_le32(u32 *dest, const u32 *__src, size_t count)
-{
- void *tmp = dest;
- u32 *src = (u32 *)__src;
-
- count /= 4;
- while (count--)
- *dest++ = swab32p(src++);
- return tmp;
-}
-
-#else
-
-static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count)
-{
- return memcpy(dest, src, count);
-}
-
-#endif /* __BIG_ENDIAN */
-
-#endif /* _IEEE1394_TYPES_H */
diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
deleted file mode 100644
index 1cf6487b65ba..000000000000
--- a/drivers/ieee1394/iso.c
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * kernel ISO transmission/reception
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-
-#include "hosts.h"
-#include "iso.h"
-
-/**
- * hpsb_iso_stop - stop DMA
- */
-void hpsb_iso_stop(struct hpsb_iso *iso)
-{
- if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
- return;
-
- iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
- XMIT_STOP : RECV_STOP, 0);
- iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
-}
-
-/**
- * hpsb_iso_shutdown - deallocate buffer and DMA context
- */
-void hpsb_iso_shutdown(struct hpsb_iso *iso)
-{
- if (iso->flags & HPSB_ISO_DRIVER_INIT) {
- hpsb_iso_stop(iso);
- iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
- XMIT_SHUTDOWN : RECV_SHUTDOWN, 0);
- iso->flags &= ~HPSB_ISO_DRIVER_INIT;
- }
-
- dma_region_free(&iso->data_buf);
- kfree(iso);
-}
-
-static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
- enum hpsb_iso_type type,
- unsigned int data_buf_size,
- unsigned int buf_packets,
- int channel, int dma_mode,
- int irq_interval,
- void (*callback) (struct hpsb_iso
- *))
-{
- struct hpsb_iso *iso;
- int dma_direction;
-
- /* make sure driver supports the ISO API */
- if (!host->driver->isoctl) {
- printk(KERN_INFO
- "ieee1394: host driver '%s' does not support the rawiso API\n",
- host->driver->name);
- return NULL;
- }
-
- /* sanitize parameters */
-
- if (buf_packets < 2)
- buf_packets = 2;
-
- if ((dma_mode < HPSB_ISO_DMA_DEFAULT)
- || (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
- dma_mode = HPSB_ISO_DMA_DEFAULT;
-
- if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
- irq_interval = buf_packets / 4;
- if (irq_interval == 0) /* really interrupt for each packet */
- irq_interval = 1;
-
- if (channel < -1 || channel >= 64)
- return NULL;
-
- /* channel = -1 is OK for multi-channel recv but not for xmit */
- if (type == HPSB_ISO_XMIT && channel < 0)
- return NULL;
-
- /* allocate and write the struct hpsb_iso */
-
- iso =
- kmalloc(sizeof(*iso) +
- buf_packets * sizeof(struct hpsb_iso_packet_info),
- GFP_KERNEL);
- if (!iso)
- return NULL;
-
- iso->infos = (struct hpsb_iso_packet_info *)(iso + 1);
-
- iso->type = type;
- iso->host = host;
- iso->hostdata = NULL;
- iso->callback = callback;
- init_waitqueue_head(&iso->waitq);
- iso->channel = channel;
- iso->irq_interval = irq_interval;
- iso->dma_mode = dma_mode;
- dma_region_init(&iso->data_buf);
- iso->buf_size = PAGE_ALIGN(data_buf_size);
- iso->buf_packets = buf_packets;
- iso->pkt_dma = 0;
- iso->first_packet = 0;
- spin_lock_init(&iso->lock);
-
- if (iso->type == HPSB_ISO_XMIT) {
- iso->n_ready_packets = iso->buf_packets;
- dma_direction = PCI_DMA_TODEVICE;
- } else {
- iso->n_ready_packets = 0;
- dma_direction = PCI_DMA_FROMDEVICE;
- }
-
- atomic_set(&iso->overflows, 0);
- iso->bytes_discarded = 0;
- iso->flags = 0;
- iso->prebuffer = 0;
-
- /* allocate the packet buffer */
- if (dma_region_alloc
- (&iso->data_buf, iso->buf_size, host->pdev, dma_direction))
- goto err;
-
- return iso;
-
- err:
- hpsb_iso_shutdown(iso);
- return NULL;
-}
-
-/**
- * hpsb_iso_n_ready - returns number of packets ready to send or receive
- */
-int hpsb_iso_n_ready(struct hpsb_iso *iso)
-{
- unsigned long flags;
- int val;
-
- spin_lock_irqsave(&iso->lock, flags);
- val = iso->n_ready_packets;
- spin_unlock_irqrestore(&iso->lock, flags);
-
- return val;
-}
-
-/**
- * hpsb_iso_xmit_init - allocate the buffer and DMA context
- */
-struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
- unsigned int data_buf_size,
- unsigned int buf_packets,
- int channel,
- int speed,
- int irq_interval,
- void (*callback) (struct hpsb_iso *))
-{
- struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT,
- data_buf_size, buf_packets,
- channel,
- HPSB_ISO_DMA_DEFAULT,
- irq_interval, callback);
- if (!iso)
- return NULL;
-
- iso->speed = speed;
-
- /* tell the driver to start working */
- if (host->driver->isoctl(iso, XMIT_INIT, 0))
- goto err;
-
- iso->flags |= HPSB_ISO_DRIVER_INIT;
- return iso;
-
- err:
- hpsb_iso_shutdown(iso);
- return NULL;
-}
-
-/**
- * hpsb_iso_recv_init - allocate the buffer and DMA context
- *
- * Note, if channel = -1, multi-channel receive is enabled.
- */
-struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
- unsigned int data_buf_size,
- unsigned int buf_packets,
- int channel,
- int dma_mode,
- int irq_interval,
- void (*callback) (struct hpsb_iso *))
-{
- struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV,
- data_buf_size, buf_packets,
- channel, dma_mode,
- irq_interval, callback);
- if (!iso)
- return NULL;
-
- /* tell the driver to start working */
- if (host->driver->isoctl(iso, RECV_INIT, 0))
- goto err;
-
- iso->flags |= HPSB_ISO_DRIVER_INIT;
- return iso;
-
- err:
- hpsb_iso_shutdown(iso);
- return NULL;
-}
-
-/**
- * hpsb_iso_recv_listen_channel
- *
- * multi-channel only
- */
-int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
-{
- if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
- return -EINVAL;
- return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
-}
-
-/**
- * hpsb_iso_recv_unlisten_channel
- *
- * multi-channel only
- */
-int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
-{
- if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
- return -EINVAL;
- return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
-}
-
-/**
- * hpsb_iso_recv_set_channel_mask
- *
- * multi-channel only
- */
-int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
-{
- if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
- return -EINVAL;
- return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK,
- (unsigned long)&mask);
-}
-
-/**
- * hpsb_iso_recv_flush - check for arrival of new packets
- *
- * check for arrival of new packets immediately (even if irq_interval
- * has not yet been reached)
- */
-int hpsb_iso_recv_flush(struct hpsb_iso *iso)
-{
- if (iso->type != HPSB_ISO_RECV)
- return -EINVAL;
- return iso->host->driver->isoctl(iso, RECV_FLUSH, 0);
-}
-
-static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
-{
- int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle);
- if (retval)
- return retval;
-
- iso->flags |= HPSB_ISO_DRIVER_STARTED;
- return retval;
-}
-
-/**
- * hpsb_iso_xmit_start - start DMA
- */
-int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
-{
- if (iso->type != HPSB_ISO_XMIT)
- return -1;
-
- if (iso->flags & HPSB_ISO_DRIVER_STARTED)
- return 0;
-
- if (cycle < -1)
- cycle = -1;
- else if (cycle >= 8000)
- cycle %= 8000;
-
- iso->xmit_cycle = cycle;
-
- if (prebuffer < 0)
- prebuffer = iso->buf_packets - 1;
- else if (prebuffer == 0)
- prebuffer = 1;
-
- if (prebuffer >= iso->buf_packets)
- prebuffer = iso->buf_packets - 1;
-
- iso->prebuffer = prebuffer;
-
- /* remember the starting cycle; DMA will commence from xmit_queue_packets()
- once enough packets have been buffered */
- iso->start_cycle = cycle;
-
- return 0;
-}
-
-/**
- * hpsb_iso_recv_start - start DMA
- */
-int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
-{
- int retval = 0;
- int isoctl_args[3];
-
- if (iso->type != HPSB_ISO_RECV)
- return -1;
-
- if (iso->flags & HPSB_ISO_DRIVER_STARTED)
- return 0;
-
- if (cycle < -1)
- cycle = -1;
- else if (cycle >= 8000)
- cycle %= 8000;
-
- isoctl_args[0] = cycle;
-
- if (tag_mask < 0)
- /* match all tags */
- tag_mask = 0xF;
- isoctl_args[1] = tag_mask;
-
- isoctl_args[2] = sync;
-
- retval =
- iso->host->driver->isoctl(iso, RECV_START,
- (unsigned long)&isoctl_args[0]);
- if (retval)
- return retval;
-
- iso->flags |= HPSB_ISO_DRIVER_STARTED;
- return retval;
-}
-
-/* check to make sure the user has not supplied bogus values of offset/len
- * that would cause the kernel to access memory outside the buffer */
-static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
- unsigned int offset, unsigned short len,
- unsigned int *out_offset,
- unsigned short *out_len)
-{
- if (offset >= iso->buf_size)
- return -EFAULT;
-
- /* make sure the packet does not go beyond the end of the buffer */
- if (offset + len > iso->buf_size)
- return -EFAULT;
-
- /* check for wrap-around */
- if (offset + len < offset)
- return -EFAULT;
-
- /* now we can trust 'offset' and 'length' */
- *out_offset = offset;
- *out_len = len;
-
- return 0;
-}
-
-/**
- * hpsb_iso_xmit_queue_packet - queue a packet for transmission.
- *
- * @offset is relative to the beginning of the DMA buffer, where the packet's
- * data payload should already have been placed.
- */
-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
- u8 tag, u8 sy)
-{
- struct hpsb_iso_packet_info *info;
- unsigned long flags;
- int rv;
-
- if (iso->type != HPSB_ISO_XMIT)
- return -EINVAL;
-
- /* is there space in the buffer? */
- if (iso->n_ready_packets <= 0) {
- return -EBUSY;
- }
-
- info = &iso->infos[iso->first_packet];
-
- /* check for bogus offset/length */
- if (hpsb_iso_check_offset_len
- (iso, offset, len, &info->offset, &info->len))
- return -EFAULT;
-
- info->tag = tag;
- info->sy = sy;
-
- spin_lock_irqsave(&iso->lock, flags);
-
- rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long)info);
- if (rv)
- goto out;
-
- /* increment cursors */
- iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
- iso->xmit_cycle = (iso->xmit_cycle + 1) % 8000;
- iso->n_ready_packets--;
-
- if (iso->prebuffer != 0) {
- iso->prebuffer--;
- if (iso->prebuffer <= 0) {
- iso->prebuffer = 0;
- rv = do_iso_xmit_start(iso, iso->start_cycle);
- }
- }
-
- out:
- spin_unlock_irqrestore(&iso->lock, flags);
- return rv;
-}
-
-/**
- * hpsb_iso_xmit_sync - wait until all queued packets have been transmitted
- */
-int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
-{
- if (iso->type != HPSB_ISO_XMIT)
- return -EINVAL;
-
- return wait_event_interruptible(iso->waitq,
- hpsb_iso_n_ready(iso) ==
- iso->buf_packets);
-}
-
-/**
- * hpsb_iso_packet_sent
- *
- * Available to low-level drivers.
- *
- * Call after a packet has been transmitted to the bus (interrupt context is
- * OK). @cycle is the _exact_ cycle the packet was sent on. @error should be
- * non-zero if some sort of error occurred when sending the packet.
- */
-void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
-{
- unsigned long flags;
- spin_lock_irqsave(&iso->lock, flags);
-
- /* predict the cycle of the next packet to be queued */
-
- /* jump ahead by the number of packets that are already buffered */
- cycle += iso->buf_packets - iso->n_ready_packets;
- cycle %= 8000;
-
- iso->xmit_cycle = cycle;
- iso->n_ready_packets++;
- iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
-
- if (iso->n_ready_packets == iso->buf_packets || error != 0) {
- /* the buffer has run empty! */
- atomic_inc(&iso->overflows);
- }
-
- spin_unlock_irqrestore(&iso->lock, flags);
-}
-
-/**
- * hpsb_iso_packet_received
- *
- * Available to low-level drivers.
- *
- * Call after a packet has been received (interrupt context is OK).
- */
-void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
- u16 total_len, u16 cycle, u8 channel, u8 tag,
- u8 sy)
-{
- unsigned long flags;
- spin_lock_irqsave(&iso->lock, flags);
-
- if (iso->n_ready_packets == iso->buf_packets) {
- /* overflow! */
- atomic_inc(&iso->overflows);
- /* Record size of this discarded packet */
- iso->bytes_discarded += total_len;
- } else {
- struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
- info->offset = offset;
- info->len = len;
- info->total_len = total_len;
- info->cycle = cycle;
- info->channel = channel;
- info->tag = tag;
- info->sy = sy;
-
- iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
- iso->n_ready_packets++;
- }
-
- spin_unlock_irqrestore(&iso->lock, flags);
-}
-
-/**
- * hpsb_iso_recv_release_packets - release packets, reuse buffer
- *
- * @n_packets have been read out of the buffer, re-use the buffer space
- */
-int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
-{
- unsigned long flags;
- unsigned int i;
- int rv = 0;
-
- if (iso->type != HPSB_ISO_RECV)
- return -1;
-
- spin_lock_irqsave(&iso->lock, flags);
- for (i = 0; i < n_packets; i++) {
- rv = iso->host->driver->isoctl(iso, RECV_RELEASE,
- (unsigned long)&iso->infos[iso->
- first_packet]);
- if (rv)
- break;
-
- iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
- iso->n_ready_packets--;
-
- /* release memory from packets discarded when queue was full */
- if (iso->n_ready_packets == 0) { /* Release only after all prior packets handled */
- if (iso->bytes_discarded != 0) {
- struct hpsb_iso_packet_info inf;
- inf.total_len = iso->bytes_discarded;
- iso->host->driver->isoctl(iso, RECV_RELEASE,
- (unsigned long)&inf);
- iso->bytes_discarded = 0;
- }
- }
- }
- spin_unlock_irqrestore(&iso->lock, flags);
- return rv;
-}
-
-/**
- * hpsb_iso_wake
- *
- * Available to low-level drivers.
- *
- * Call to wake waiting processes after buffer space has opened up.
- */
-void hpsb_iso_wake(struct hpsb_iso *iso)
-{
- wake_up_interruptible(&iso->waitq);
-
- if (iso->callback)
- iso->callback(iso);
-}
diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
deleted file mode 100644
index c2089c093aa7..000000000000
--- a/drivers/ieee1394/iso.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * kernel ISO transmission/reception
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#ifndef IEEE1394_ISO_H
-#define IEEE1394_ISO_H
-
-#include <linux/spinlock_types.h>
-#include <linux/wait.h>
-#include <asm/atomic.h>
-#include <asm/types.h>
-
-#include "dma.h"
-
-struct hpsb_host;
-
-/* high-level ISO interface */
-
-/*
- * This API sends and receives isochronous packets on a large,
- * virtually-contiguous kernel memory buffer. The buffer may be mapped
- * into a user-space process for zero-copy transmission and reception.
- *
- * There are no explicit boundaries between packets in the buffer. A
- * packet may be transmitted or received at any location. However,
- * low-level drivers may impose certain restrictions on alignment or
- * size of packets. (e.g. in OHCI no packet may cross a page boundary,
- * and packets should be quadlet-aligned)
- */
-
-/* Packet descriptor - the API maintains a ring buffer of these packet
- * descriptors in kernel memory (hpsb_iso.infos[]). */
-struct hpsb_iso_packet_info {
- /* offset of data payload relative to the first byte of the buffer */
- __u32 offset;
-
- /* length of the data payload, in bytes (not including the isochronous
- * header) */
- __u16 len;
-
- /* (recv only) the cycle number (mod 8000) on which the packet was
- * received */
- __u16 cycle;
-
- /* (recv only) channel on which the packet was received */
- __u8 channel;
-
- /* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */
- __u8 tag;
- __u8 sy;
-
- /* length in bytes of the packet including header/trailer.
- * MUST be at structure end, since the first part of this structure is
- * also defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is
- * copied to userspace and is accessed there through libraw1394. */
- __u16 total_len;
-};
-
-enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 };
-
-/* The mode of the dma when receiving iso data. Must be supported by chip */
-enum raw1394_iso_dma_recv_mode {
- HPSB_ISO_DMA_DEFAULT = -1,
- HPSB_ISO_DMA_OLD_ABI = 0,
- HPSB_ISO_DMA_BUFFERFILL = 1,
- HPSB_ISO_DMA_PACKET_PER_BUFFER = 2
-};
-
-struct hpsb_iso {
- enum hpsb_iso_type type;
-
- /* pointer to low-level driver and its private data */
- struct hpsb_host *host;
- void *hostdata;
-
- /* a function to be called (from interrupt context) after
- * outgoing packets have been sent, or incoming packets have
- * arrived */
- void (*callback)(struct hpsb_iso*);
-
- /* wait for buffer space */
- wait_queue_head_t waitq;
-
- int speed; /* IEEE1394_SPEED_100, 200, or 400 */
- int channel; /* -1 if multichannel */
- int dma_mode; /* dma receive mode */
-
-
- /* greatest # of packets between interrupts - controls
- * the maximum latency of the buffer */
- int irq_interval;
-
- /* the buffer for packet data payloads */
- struct dma_region data_buf;
-
- /* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */
- unsigned int buf_size;
-
- /* # of packets in the ringbuffer */
- unsigned int buf_packets;
-
- /* protects packet cursors */
- spinlock_t lock;
-
- /* the index of the next packet that will be produced
- or consumed by the user */
- int first_packet;
-
- /* the index of the next packet that will be transmitted
- or received by the 1394 hardware */
- int pkt_dma;
-
- /* how many packets, starting at first_packet:
- * (transmit) are ready to be filled with data
- * (receive) contain received data */
- int n_ready_packets;
-
- /* how many times the buffer has overflowed or underflowed */
- atomic_t overflows;
- /* how many cycles were skipped for a given context */
- atomic_t skips;
-
- /* Current number of bytes lost in discarded packets */
- int bytes_discarded;
-
- /* private flags to track initialization progress */
-#define HPSB_ISO_DRIVER_INIT (1<<0)
-#define HPSB_ISO_DRIVER_STARTED (1<<1)
- unsigned int flags;
-
- /* # of packets left to prebuffer (xmit only) */
- int prebuffer;
-
- /* starting cycle for DMA (xmit only) */
- int start_cycle;
-
- /* cycle at which next packet will be transmitted,
- * -1 if not known */
- int xmit_cycle;
-
- /* ringbuffer of packet descriptors in regular kernel memory
- * XXX Keep this last, since we use over-allocated memory from
- * this entry to fill this field. */
- struct hpsb_iso_packet_info *infos;
-};
-
-/* functions available to high-level drivers (e.g. raw1394) */
-
-struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
- unsigned int data_buf_size,
- unsigned int buf_packets,
- int channel,
- int speed,
- int irq_interval,
- void (*callback)(struct hpsb_iso*));
-struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
- unsigned int data_buf_size,
- unsigned int buf_packets,
- int channel,
- int dma_mode,
- int irq_interval,
- void (*callback)(struct hpsb_iso*));
-int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel);
-int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
-int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
-int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle,
- int prebuffer);
-int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle,
- int tag_mask, int sync);
-void hpsb_iso_stop(struct hpsb_iso *iso);
-void hpsb_iso_shutdown(struct hpsb_iso *iso);
-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
- u8 tag, u8 sy);
-int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
-int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
- unsigned int n_packets);
-int hpsb_iso_recv_flush(struct hpsb_iso *iso);
-int hpsb_iso_n_ready(struct hpsb_iso *iso);
-
-/* the following are callbacks available to low-level drivers */
-
-void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
-void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
- u16 total_len, u16 cycle, u8 channel, u8 tag,
- u8 sy);
-void hpsb_iso_wake(struct hpsb_iso *iso);
-
-#endif /* IEEE1394_ISO_H */
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
deleted file mode 100644
index 18350213479e..000000000000
--- a/drivers/ieee1394/nodemgr.c
+++ /dev/null
@@ -1,1901 +0,0 @@
-/*
- * Node information (ConfigROM) collection and management.
- *
- * Copyright (C) 2000 Andreas E. Bombe
- * 2001-2003 Ben Collins <bcollins@debian.net>
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/bitmap.h>
-#include <linux/kernel.h>
-#include <linux/kmemcheck.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/mutex.h>
-#include <linux/freezer.h>
-#include <asm/atomic.h>
-
-#include "csr.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "ieee1394_transactions.h"
-#include "nodemgr.h"
-
-static int ignore_drivers;
-module_param(ignore_drivers, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");
-
-struct nodemgr_csr_info {
- struct hpsb_host *host;
- nodeid_t nodeid;
- unsigned int generation;
-
- kmemcheck_bitfield_begin(flags);
- unsigned int speed_unverified:1;
- kmemcheck_bitfield_end(flags);
-};
-
-
-/*
- * Correct the speed map entry. This is necessary
- * - for nodes with link speed < phy speed,
- * - for 1394b nodes with negotiated phy port speed < IEEE1394_SPEED_MAX.
- * A possible speed is determined by trial and error, using quadlet reads.
- */
-static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
- quadlet_t *buffer)
-{
- quadlet_t q;
- u8 i, *speed, old_speed, good_speed;
- int error;
-
- speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]);
- old_speed = *speed;
- good_speed = IEEE1394_SPEED_MAX + 1;
-
- /* Try every speed from S100 to old_speed.
- * If we did it the other way around, a too low speed could be caught
- * if the retry succeeded for some other reason, e.g. because the link
- * just finished its initialization. */
- for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {
- *speed = i;
- error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
- &q, 4);
- if (error)
- break;
- *buffer = q;
- good_speed = i;
- }
- if (good_speed <= IEEE1394_SPEED_MAX) {
- HPSB_DEBUG("Speed probe of node " NODE_BUS_FMT " yields %s",
- NODE_BUS_ARGS(ci->host, ci->nodeid),
- hpsb_speedto_str[good_speed]);
- *speed = good_speed;
- ci->speed_unverified = 0;
- return 0;
- }
- *speed = old_speed;
- return error;
-}
-
-static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr,
- void *buffer, void *__ci)
-{
- struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
- int i, error;
-
- for (i = 1; ; i++) {
- error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
- buffer, 4);
- if (!error) {
- ci->speed_unverified = 0;
- break;
- }
- /* Give up after 3rd failure. */
- if (i == 3)
- break;
-
- /* The ieee1394_core guessed the node's speed capability from
- * the self ID. Check whether a lower speed works. */
- if (ci->speed_unverified) {
- error = nodemgr_check_speed(ci, addr, buffer);
- if (!error)
- break;
- }
- if (msleep_interruptible(334))
- return -EINTR;
- }
- return error;
-}
-
-static struct csr1212_bus_ops nodemgr_csr_ops = {
- .bus_read = nodemgr_bus_read,
-};
-
-
-/*
- * Basically what we do here is start off retrieving the bus_info block.
- * From there will fill in some info about the node, verify it is of IEEE
- * 1394 type, and that the crc checks out ok. After that we start off with
- * the root directory, and subdirectories. To do this, we retrieve the
- * quadlet header for a directory, find out the length, and retrieve the
- * complete directory entry (be it a leaf or a directory). We then process
- * it and add the info to our structure for that particular node.
- *
- * We verify CRC's along the way for each directory/block/leaf. The entire
- * node structure is generic, and simply stores the information in a way
- * that's easy to parse by the protocol interface.
- */
-
-/*
- * The nodemgr relies heavily on the Driver Model for device callbacks and
- * driver/device mappings. The old nodemgr used to handle all this itself,
- * but now we are much simpler because of the LDM.
- */
-
-struct host_info {
- struct hpsb_host *host;
- struct list_head list;
- struct task_struct *thread;
-};
-
-static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
-
-struct bus_type ieee1394_bus_type = {
- .name = "ieee1394",
- .match = nodemgr_bus_match,
-};
-
-static void host_cls_release(struct device *dev)
-{
- put_device(&container_of((dev), struct hpsb_host, host_dev)->device);
-}
-
-struct class hpsb_host_class = {
- .name = "ieee1394_host",
- .dev_release = host_cls_release,
-};
-
-static void ne_cls_release(struct device *dev)
-{
- put_device(&container_of((dev), struct node_entry, node_dev)->device);
-}
-
-static struct class nodemgr_ne_class = {
- .name = "ieee1394_node",
- .dev_release = ne_cls_release,
-};
-
-static void ud_cls_release(struct device *dev)
-{
- put_device(&container_of((dev), struct unit_directory, unit_dev)->device);
-}
-
-/* The name here is only so that unit directory hotplug works with old
- * style hotplug, which only ever did unit directories anyway.
- */
-static struct class nodemgr_ud_class = {
- .name = "ieee1394",
- .dev_release = ud_cls_release,
- .dev_uevent = nodemgr_uevent,
-};
-
-static struct hpsb_highlevel nodemgr_highlevel;
-
-
-static void nodemgr_release_ud(struct device *dev)
-{
- struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-
- if (ud->vendor_name_kv)
- csr1212_release_keyval(ud->vendor_name_kv);
- if (ud->model_name_kv)
- csr1212_release_keyval(ud->model_name_kv);
-
- kfree(ud);
-}
-
-static void nodemgr_release_ne(struct device *dev)
-{
- struct node_entry *ne = container_of(dev, struct node_entry, device);
-
- if (ne->vendor_name_kv)
- csr1212_release_keyval(ne->vendor_name_kv);
-
- kfree(ne);
-}
-
-
-static void nodemgr_release_host(struct device *dev)
-{
- struct hpsb_host *host = container_of(dev, struct hpsb_host, device);
-
- csr1212_destroy_csr(host->csr.rom);
-
- kfree(host);
-}
-
-static int nodemgr_ud_platform_data;
-
-static struct device nodemgr_dev_template_ud = {
- .bus = &ieee1394_bus_type,
- .release = nodemgr_release_ud,
- .platform_data = &nodemgr_ud_platform_data,
-};
-
-static struct device nodemgr_dev_template_ne = {
- .bus = &ieee1394_bus_type,
- .release = nodemgr_release_ne,
-};
-
-/* This dummy driver prevents the host devices from being scanned. We have no
- * useful drivers for them yet, and there would be a deadlock possible if the
- * driver core scans the host device while the host's low-level driver (i.e.
- * the host's parent device) is being removed. */
-static struct device_driver nodemgr_mid_layer_driver = {
- .bus = &ieee1394_bus_type,
- .name = "nodemgr",
- .owner = THIS_MODULE,
-};
-
-struct device nodemgr_dev_template_host = {
- .bus = &ieee1394_bus_type,
- .release = nodemgr_release_host,
-};
-
-
-#define fw_attr(class, class_type, field, type, format_string) \
-static ssize_t fw_show_##class##_##field (struct device *dev, struct device_attribute *attr, char *buf)\
-{ \
- class_type *class; \
- class = container_of(dev, class_type, device); \
- return sprintf(buf, format_string, (type)class->field); \
-} \
-static struct device_attribute dev_attr_##class##_##field = { \
- .attr = {.name = __stringify(field), .mode = S_IRUGO }, \
- .show = fw_show_##class##_##field, \
-};
-
-#define fw_attr_td(class, class_type, td_kv) \
-static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attribute *attr, char *buf)\
-{ \
- int len; \
- class_type *class = container_of(dev, class_type, device); \
- len = (class->td_kv->value.leaf.len - 2) * sizeof(quadlet_t); \
- memcpy(buf, \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv), \
- len); \
- while (buf[len - 1] == '\0') \
- len--; \
- buf[len++] = '\n'; \
- buf[len] = '\0'; \
- return len; \
-} \
-static struct device_attribute dev_attr_##class##_##td_kv = { \
- .attr = {.name = __stringify(td_kv), .mode = S_IRUGO }, \
- .show = fw_show_##class##_##td_kv, \
-};
-
-
-#define fw_drv_attr(field, type, format_string) \
-static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \
-{ \
- struct hpsb_protocol_driver *driver; \
- driver = container_of(drv, struct hpsb_protocol_driver, driver); \
- return sprintf(buf, format_string, (type)driver->field);\
-} \
-static struct driver_attribute driver_attr_drv_##field = { \
- .attr = {.name = __stringify(field), .mode = S_IRUGO }, \
- .show = fw_drv_show_##field, \
-};
-
-
-static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct node_entry *ne = container_of(dev, struct node_entry, device);
-
- return sprintf(buf, "IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d) "
- "LSPD(%d) MAX_REC(%d) MAX_ROM(%d) CYC_CLK_ACC(%d)\n",
- ne->busopt.irmc,
- ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
- ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,
- ne->busopt.max_rec,
- ne->busopt.max_rom,
- ne->busopt.cyc_clk_acc);
-}
-static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
-
-
-#ifdef HPSB_DEBUG_TLABELS
-static ssize_t fw_show_ne_tlabels_free(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct node_entry *ne = container_of(dev, struct node_entry, device);
- unsigned long flags;
- unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
- int tf;
-
- spin_lock_irqsave(&hpsb_tlabel_lock, flags);
- tf = 64 - bitmap_weight(tp, 64);
- spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
- return sprintf(buf, "%d\n", tf);
-}
-static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
-
-
-static ssize_t fw_show_ne_tlabels_mask(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct node_entry *ne = container_of(dev, struct node_entry, device);
- unsigned long flags;
- unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
- u64 tm;
-
- spin_lock_irqsave(&hpsb_tlabel_lock, flags);
-#if (BITS_PER_LONG <= 32)
- tm = ((u64)tp[0] << 32) + tp[1];
-#else
- tm = tp[0];
-#endif
- spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
- return sprintf(buf, "0x%016llx\n", (unsigned long long)tm);
-}
-static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
-#endif /* HPSB_DEBUG_TLABELS */
-
-
-static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- struct unit_directory *ud = container_of(dev, struct unit_directory, device);
- int state = simple_strtoul(buf, NULL, 10);
-
- if (state == 1) {
- ud->ignore_driver = 1;
- device_release_driver(dev);
- } else if (state == 0)
- ud->ignore_driver = 0;
-
- return count;
-}
-static ssize_t fw_get_ignore_driver(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-
- return sprintf(buf, "%d\n", ud->ignore_driver);
-}
-static DEVICE_ATTR(ignore_driver, S_IWUSR | S_IRUGO, fw_get_ignore_driver, fw_set_ignore_driver);
-
-
-static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf,
- size_t count)
-{
- int error = 0;
-
- if (simple_strtoul(buf, NULL, 10) == 1)
- error = bus_rescan_devices(&ieee1394_bus_type);
- return error ? error : count;
-}
-static ssize_t fw_get_rescan(struct bus_type *bus, char *buf)
-{
- return sprintf(buf, "You can force a rescan of the bus for "
- "drivers by writing a 1 to this file\n");
-}
-static BUS_ATTR(rescan, S_IWUSR | S_IRUGO, fw_get_rescan, fw_set_rescan);
-
-
-static ssize_t fw_set_ignore_drivers(struct bus_type *bus, const char *buf, size_t count)
-{
- int state = simple_strtoul(buf, NULL, 10);
-
- if (state == 1)
- ignore_drivers = 1;
- else if (state == 0)
- ignore_drivers = 0;
-
- return count;
-}
-static ssize_t fw_get_ignore_drivers(struct bus_type *bus, char *buf)
-{
- return sprintf(buf, "%d\n", ignore_drivers);
-}
-static BUS_ATTR(ignore_drivers, S_IWUSR | S_IRUGO, fw_get_ignore_drivers, fw_set_ignore_drivers);
-
-
-struct bus_attribute *const fw_bus_attrs[] = {
- &bus_attr_rescan,
- &bus_attr_ignore_drivers,
- NULL
-};
-
-
-fw_attr(ne, struct node_entry, capabilities, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n")
-
-fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
-fw_attr_td(ne, struct node_entry, vendor_name_kv)
-
-fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
-fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");
-
-static struct device_attribute *const fw_ne_attrs[] = {
- &dev_attr_ne_guid,
- &dev_attr_ne_guid_vendor_id,
- &dev_attr_ne_capabilities,
- &dev_attr_ne_vendor_id,
- &dev_attr_ne_nodeid,
- &dev_attr_bus_options,
-#ifdef HPSB_DEBUG_TLABELS
- &dev_attr_tlabels_free,
- &dev_attr_tlabels_mask,
-#endif
-};
-
-
-
-fw_attr(ud, struct unit_directory, address, unsigned long long, "0x%016Lx\n")
-fw_attr(ud, struct unit_directory, length, int, "%d\n")
-/* These are all dependent on the value being provided */
-fw_attr(ud, struct unit_directory, vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, model_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
-fw_attr_td(ud, struct unit_directory, vendor_name_kv)
-fw_attr_td(ud, struct unit_directory, model_name_kv)
-
-static struct device_attribute *const fw_ud_attrs[] = {
- &dev_attr_ud_address,
- &dev_attr_ud_length,
- &dev_attr_ignore_driver,
-};
-
-
-fw_attr(host, struct hpsb_host, node_count, int, "%d\n")
-fw_attr(host, struct hpsb_host, selfid_count, int, "%d\n")
-fw_attr(host, struct hpsb_host, nodes_active, int, "%d\n")
-fw_attr(host, struct hpsb_host, in_bus_reset, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_root, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_cycmst, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_irm, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_busmgr, int, "%d\n")
-
-static struct device_attribute *const fw_host_attrs[] = {
- &dev_attr_host_node_count,
- &dev_attr_host_selfid_count,
- &dev_attr_host_nodes_active,
- &dev_attr_host_in_bus_reset,
- &dev_attr_host_is_root,
- &dev_attr_host_is_cycmst,
- &dev_attr_host_is_irm,
- &dev_attr_host_is_busmgr,
-};
-
-
-static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
-{
- struct hpsb_protocol_driver *driver;
- const struct ieee1394_device_id *id;
- int length = 0;
- char *scratch = buf;
-
- driver = container_of(drv, struct hpsb_protocol_driver, driver);
- id = driver->id_table;
- if (!id)
- return 0;
-
- for (; id->match_flags != 0; id++) {
- int need_coma = 0;
-
- if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) {
- length += sprintf(scratch, "vendor_id=0x%06x", id->vendor_id);
- scratch = buf + length;
- need_coma++;
- }
-
- if (id->match_flags & IEEE1394_MATCH_MODEL_ID) {
- length += sprintf(scratch, "%smodel_id=0x%06x",
- need_coma++ ? "," : "",
- id->model_id);
- scratch = buf + length;
- }
-
- if (id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) {
- length += sprintf(scratch, "%sspecifier_id=0x%06x",
- need_coma++ ? "," : "",
- id->specifier_id);
- scratch = buf + length;
- }
-
- if (id->match_flags & IEEE1394_MATCH_VERSION) {
- length += sprintf(scratch, "%sversion=0x%06x",
- need_coma++ ? "," : "",
- id->version);
- scratch = buf + length;
- }
-
- if (need_coma) {
- *scratch++ = '\n';
- length++;
- }
- }
-
- return length;
-}
-static DRIVER_ATTR(device_ids,S_IRUGO,fw_show_drv_device_ids,NULL);
-
-
-fw_drv_attr(name, const char *, "%s\n")
-
-static struct driver_attribute *const fw_drv_attrs[] = {
- &driver_attr_drv_name,
- &driver_attr_device_ids,
-};
-
-
-static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver)
-{
- struct device_driver *drv = &driver->driver;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
- if (driver_create_file(drv, fw_drv_attrs[i]))
- goto fail;
- return;
-fail:
- HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static void nodemgr_remove_drv_files(struct hpsb_protocol_driver *driver)
-{
- struct device_driver *drv = &driver->driver;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
- driver_remove_file(drv, fw_drv_attrs[i]);
-}
-
-
-static void nodemgr_create_ne_dev_files(struct node_entry *ne)
-{
- struct device *dev = &ne->device;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++)
- if (device_create_file(dev, fw_ne_attrs[i]))
- goto fail;
- return;
-fail:
- HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static void nodemgr_create_host_dev_files(struct hpsb_host *host)
-{
- struct device *dev = &host->device;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_host_attrs); i++)
- if (device_create_file(dev, fw_host_attrs[i]))
- goto fail;
- return;
-fail:
- HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
- nodeid_t nodeid);
-
-static void nodemgr_update_host_dev_links(struct hpsb_host *host)
-{
- struct device *dev = &host->device;
- struct node_entry *ne;
-
- sysfs_remove_link(&dev->kobj, "irm_id");
- sysfs_remove_link(&dev->kobj, "busmgr_id");
- sysfs_remove_link(&dev->kobj, "host_id");
-
- if ((ne = find_entry_by_nodeid(host, host->irm_id)) &&
- sysfs_create_link(&dev->kobj, &ne->device.kobj, "irm_id"))
- goto fail;
- if ((ne = find_entry_by_nodeid(host, host->busmgr_id)) &&
- sysfs_create_link(&dev->kobj, &ne->device.kobj, "busmgr_id"))
- goto fail;
- if ((ne = find_entry_by_nodeid(host, host->node_id)) &&
- sysfs_create_link(&dev->kobj, &ne->device.kobj, "host_id"))
- goto fail;
- return;
-fail:
- HPSB_ERR("Failed to update sysfs attributes for host %d", host->id);
-}
-
-static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
-{
- struct device *dev = &ud->device;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_ud_attrs); i++)
- if (device_create_file(dev, fw_ud_attrs[i]))
- goto fail;
- if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
- if (device_create_file(dev, &dev_attr_ud_specifier_id))
- goto fail;
- if (ud->flags & UNIT_DIRECTORY_VERSION)
- if (device_create_file(dev, &dev_attr_ud_version))
- goto fail;
- if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {
- if (device_create_file(dev, &dev_attr_ud_vendor_id))
- goto fail;
- if (ud->vendor_name_kv &&
- device_create_file(dev, &dev_attr_ud_vendor_name_kv))
- goto fail;
- }
- if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {
- if (device_create_file(dev, &dev_attr_ud_model_id))
- goto fail;
- if (ud->model_name_kv &&
- device_create_file(dev, &dev_attr_ud_model_name_kv))
- goto fail;
- }
- return;
-fail:
- HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
-{
- struct hpsb_protocol_driver *driver;
- struct unit_directory *ud;
- const struct ieee1394_device_id *id;
-
- /* We only match unit directories */
- if (dev->platform_data != &nodemgr_ud_platform_data)
- return 0;
-
- ud = container_of(dev, struct unit_directory, device);
- if (ud->ne->in_limbo || ud->ignore_driver)
- return 0;
-
- /* We only match drivers of type hpsb_protocol_driver */
- if (drv == &nodemgr_mid_layer_driver)
- return 0;
-
- driver = container_of(drv, struct hpsb_protocol_driver, driver);
- id = driver->id_table;
- if (!id)
- return 0;
-
- for (; id->match_flags != 0; id++) {
- if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
- id->vendor_id != ud->vendor_id)
- continue;
-
- if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) &&
- id->model_id != ud->model_id)
- continue;
-
- if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&
- id->specifier_id != ud->specifier_id)
- continue;
-
- if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
- id->version != ud->version)
- continue;
-
- return 1;
- }
-
- return 0;
-}
-
-
-static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
-
-static int match_ne(struct device *dev, void *data)
-{
- struct unit_directory *ud;
- struct node_entry *ne = data;
-
- ud = container_of(dev, struct unit_directory, unit_dev);
- return ud->ne == ne;
-}
-
-static void nodemgr_remove_uds(struct node_entry *ne)
-{
- struct device *dev;
- struct unit_directory *ud;
-
- /* Use class_find device to iterate the devices. Since this code
- * may be called from other contexts besides the knodemgrds,
- * protect it by nodemgr_serialize_remove_uds.
- */
- mutex_lock(&nodemgr_serialize_remove_uds);
- for (;;) {
- dev = class_find_device(&nodemgr_ud_class, NULL, ne, match_ne);
- if (!dev)
- break;
- ud = container_of(dev, struct unit_directory, unit_dev);
- put_device(dev);
- device_unregister(&ud->unit_dev);
- device_unregister(&ud->device);
- }
- mutex_unlock(&nodemgr_serialize_remove_uds);
-}
-
-
-static void nodemgr_remove_ne(struct node_entry *ne)
-{
- struct device *dev;
-
- dev = get_device(&ne->device);
- if (!dev)
- return;
-
- HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
- NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
- nodemgr_remove_uds(ne);
-
- device_unregister(&ne->node_dev);
- device_unregister(dev);
-
- put_device(dev);
-}
-
-static int remove_host_dev(struct device *dev, void *data)
-{
- if (dev->bus == &ieee1394_bus_type)
- nodemgr_remove_ne(container_of(dev, struct node_entry,
- device));
- return 0;
-}
-
-static void nodemgr_remove_host_dev(struct device *dev)
-{
- device_for_each_child(dev, NULL, remove_host_dev);
- sysfs_remove_link(&dev->kobj, "irm_id");
- sysfs_remove_link(&dev->kobj, "busmgr_id");
- sysfs_remove_link(&dev->kobj, "host_id");
-}
-
-
-static void nodemgr_update_bus_options(struct node_entry *ne)
-{
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- static const u16 mr[] = { 4, 64, 1024, 0};
-#endif
- quadlet_t busoptions = be32_to_cpu(ne->csr->bus_info_data[2]);
-
- ne->busopt.irmc = (busoptions >> 31) & 1;
- ne->busopt.cmc = (busoptions >> 30) & 1;
- ne->busopt.isc = (busoptions >> 29) & 1;
- ne->busopt.bmc = (busoptions >> 28) & 1;
- ne->busopt.pmc = (busoptions >> 27) & 1;
- ne->busopt.cyc_clk_acc = (busoptions >> 16) & 0xff;
- ne->busopt.max_rec = 1 << (((busoptions >> 12) & 0xf) + 1);
- ne->busopt.max_rom = (busoptions >> 8) & 0x3;
- ne->busopt.generation = (busoptions >> 4) & 0xf;
- ne->busopt.lnkspd = busoptions & 0x7;
-
- HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d "
- "cyc_clk_acc=%d max_rec=%d max_rom=%d gen=%d lspd=%d",
- busoptions, ne->busopt.irmc, ne->busopt.cmc,
- ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc,
- ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
- mr[ne->busopt.max_rom],
- ne->busopt.generation, ne->busopt.lnkspd);
-}
-
-
-static struct node_entry *nodemgr_create_node(octlet_t guid,
- struct csr1212_csr *csr, struct hpsb_host *host,
- nodeid_t nodeid, unsigned int generation)
-{
- struct node_entry *ne;
-
- ne = kzalloc(sizeof(*ne), GFP_KERNEL);
- if (!ne)
- goto fail_alloc;
-
- ne->host = host;
- ne->nodeid = nodeid;
- ne->generation = generation;
- ne->needs_probe = true;
-
- ne->guid = guid;
- ne->guid_vendor_id = (guid >> 40) & 0xffffff;
- ne->csr = csr;
-
- memcpy(&ne->device, &nodemgr_dev_template_ne,
- sizeof(ne->device));
- ne->device.parent = &host->device;
- dev_set_name(&ne->device, "%016Lx", (unsigned long long)(ne->guid));
-
- ne->node_dev.parent = &ne->device;
- ne->node_dev.class = &nodemgr_ne_class;
- dev_set_name(&ne->node_dev, "%016Lx", (unsigned long long)(ne->guid));
-
- if (device_register(&ne->device))
- goto fail_devreg;
- if (device_register(&ne->node_dev))
- goto fail_classdevreg;
- get_device(&ne->device);
-
- nodemgr_create_ne_dev_files(ne);
-
- nodemgr_update_bus_options(ne);
-
- HPSB_DEBUG("%s added: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
- (host->node_id == nodeid) ? "Host" : "Node",
- NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
-
- return ne;
-
-fail_classdevreg:
- device_unregister(&ne->device);
-fail_devreg:
- kfree(ne);
-fail_alloc:
- HPSB_ERR("Failed to create node ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
- NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
-
- return NULL;
-}
-
-static int match_ne_guid(struct device *dev, void *data)
-{
- struct node_entry *ne;
- u64 *guid = data;
-
- ne = container_of(dev, struct node_entry, node_dev);
- return ne->guid == *guid;
-}
-
-static struct node_entry *find_entry_by_guid(u64 guid)
-{
- struct device *dev;
- struct node_entry *ne;
-
- dev = class_find_device(&nodemgr_ne_class, NULL, &guid, match_ne_guid);
- if (!dev)
- return NULL;
- ne = container_of(dev, struct node_entry, node_dev);
- put_device(dev);
-
- return ne;
-}
-
-struct match_nodeid_parameter {
- struct hpsb_host *host;
- nodeid_t nodeid;
-};
-
-static int match_ne_nodeid(struct device *dev, void *data)
-{
- int found = 0;
- struct node_entry *ne;
- struct match_nodeid_parameter *p = data;
-
- if (!dev)
- goto ret;
- ne = container_of(dev, struct node_entry, node_dev);
- if (ne->host == p->host && ne->nodeid == p->nodeid)
- found = 1;
-ret:
- return found;
-}
-
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
- nodeid_t nodeid)
-{
- struct device *dev;
- struct node_entry *ne;
- struct match_nodeid_parameter p;
-
- p.host = host;
- p.nodeid = nodeid;
-
- dev = class_find_device(&nodemgr_ne_class, NULL, &p, match_ne_nodeid);
- if (!dev)
- return NULL;
- ne = container_of(dev, struct node_entry, node_dev);
- put_device(dev);
-
- return ne;
-}
-
-
-static void nodemgr_register_device(struct node_entry *ne,
- struct unit_directory *ud, struct device *parent)
-{
- memcpy(&ud->device, &nodemgr_dev_template_ud,
- sizeof(ud->device));
-
- ud->device.parent = parent;
-
- dev_set_name(&ud->device, "%s-%u", dev_name(&ne->device), ud->id);
-
- ud->unit_dev.parent = &ud->device;
- ud->unit_dev.class = &nodemgr_ud_class;
- dev_set_name(&ud->unit_dev, "%s-%u", dev_name(&ne->device), ud->id);
-
- if (device_register(&ud->device))
- goto fail_devreg;
- if (device_register(&ud->unit_dev))
- goto fail_classdevreg;
- get_device(&ud->device);
-
- nodemgr_create_ud_dev_files(ud);
-
- return;
-
-fail_classdevreg:
- device_unregister(&ud->device);
-fail_devreg:
- HPSB_ERR("Failed to create unit %s", dev_name(&ud->device));
-}
-
-
-/* This implementation currently only scans the config rom and its
- * immediate unit directories looking for software_id and
- * software_version entries, in order to get driver autoloading working. */
-static struct unit_directory *nodemgr_process_unit_directory
- (struct node_entry *ne, struct csr1212_keyval *ud_kv,
- unsigned int *id, struct unit_directory *parent)
-{
- struct unit_directory *ud;
- struct unit_directory *ud_child = NULL;
- struct csr1212_dentry *dentry;
- struct csr1212_keyval *kv;
- u8 last_key_id = 0;
-
- ud = kzalloc(sizeof(*ud), GFP_KERNEL);
- if (!ud)
- goto unit_directory_error;
-
- ud->ne = ne;
- ud->ignore_driver = ignore_drivers;
- ud->address = ud_kv->offset + CSR1212_REGISTER_SPACE_BASE;
- ud->directory_id = ud->address & 0xffffff;
- ud->ud_kv = ud_kv;
- ud->id = (*id)++;
-
- /* inherit vendor_id from root directory if none exists in unit dir */
- ud->vendor_id = ne->vendor_id;
-
- csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) {
- switch (kv->key.id) {
- case CSR1212_KV_ID_VENDOR:
- if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
- ud->vendor_id = kv->value.immediate;
- ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
- }
- break;
-
- case CSR1212_KV_ID_MODEL:
- ud->model_id = kv->value.immediate;
- ud->flags |= UNIT_DIRECTORY_MODEL_ID;
- break;
-
- case CSR1212_KV_ID_SPECIFIER_ID:
- ud->specifier_id = kv->value.immediate;
- ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
- break;
-
- case CSR1212_KV_ID_VERSION:
- ud->version = kv->value.immediate;
- ud->flags |= UNIT_DIRECTORY_VERSION;
- break;
-
- case CSR1212_KV_ID_DESCRIPTOR:
- if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
- CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
- CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
- switch (last_key_id) {
- case CSR1212_KV_ID_VENDOR:
- csr1212_keep_keyval(kv);
- ud->vendor_name_kv = kv;
- break;
-
- case CSR1212_KV_ID_MODEL:
- csr1212_keep_keyval(kv);
- ud->model_name_kv = kv;
- break;
-
- }
- } /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */
- break;
-
- case CSR1212_KV_ID_DEPENDENT_INFO:
- /* Logical Unit Number */
- if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
- if (ud->flags & UNIT_DIRECTORY_HAS_LUN) {
- ud_child = kmemdup(ud, sizeof(*ud_child), GFP_KERNEL);
- if (!ud_child)
- goto unit_directory_error;
- nodemgr_register_device(ne, ud_child, &ne->device);
- ud_child = NULL;
-
- ud->id = (*id)++;
- }
- ud->lun = kv->value.immediate;
- ud->flags |= UNIT_DIRECTORY_HAS_LUN;
-
- /* Logical Unit Directory */
- } else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {
- /* This should really be done in SBP2 as this is
- * doing SBP2 specific parsing.
- */
-
- /* first register the parent unit */
- ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY;
- if (ud->device.bus != &ieee1394_bus_type)
- nodemgr_register_device(ne, ud, &ne->device);
-
- /* process the child unit */
- ud_child = nodemgr_process_unit_directory(ne, kv, id, ud);
-
- if (ud_child == NULL)
- break;
-
- /* inherit unspecified values, the driver core picks it up */
- if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&
- !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID))
- {
- ud_child->flags |= UNIT_DIRECTORY_MODEL_ID;
- ud_child->model_id = ud->model_id;
- }
- if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) &&
- !(ud_child->flags & UNIT_DIRECTORY_SPECIFIER_ID))
- {
- ud_child->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
- ud_child->specifier_id = ud->specifier_id;
- }
- if ((ud->flags & UNIT_DIRECTORY_VERSION) &&
- !(ud_child->flags & UNIT_DIRECTORY_VERSION))
- {
- ud_child->flags |= UNIT_DIRECTORY_VERSION;
- ud_child->version = ud->version;
- }
-
- /* register the child unit */
- ud_child->flags |= UNIT_DIRECTORY_LUN_DIRECTORY;
- nodemgr_register_device(ne, ud_child, &ud->device);
- }
-
- break;
-
- case CSR1212_KV_ID_DIRECTORY_ID:
- ud->directory_id = kv->value.immediate;
- break;
-
- default:
- break;
- }
- last_key_id = kv->key.id;
- }
-
- /* do not process child units here and only if not already registered */
- if (!parent && ud->device.bus != &ieee1394_bus_type)
- nodemgr_register_device(ne, ud, &ne->device);
-
- return ud;
-
-unit_directory_error:
- kfree(ud);
- return NULL;
-}
-
-
-static void nodemgr_process_root_directory(struct node_entry *ne)
-{
- unsigned int ud_id = 0;
- struct csr1212_dentry *dentry;
- struct csr1212_keyval *kv, *vendor_name_kv = NULL;
- u8 last_key_id = 0;
-
- ne->needs_probe = false;
-
- csr1212_for_each_dir_entry(ne->csr, kv, ne->csr->root_kv, dentry) {
- switch (kv->key.id) {
- case CSR1212_KV_ID_VENDOR:
- ne->vendor_id = kv->value.immediate;
- break;
-
- case CSR1212_KV_ID_NODE_CAPABILITIES:
- ne->capabilities = kv->value.immediate;
- break;
-
- case CSR1212_KV_ID_UNIT:
- nodemgr_process_unit_directory(ne, kv, &ud_id, NULL);
- break;
-
- case CSR1212_KV_ID_DESCRIPTOR:
- if (last_key_id == CSR1212_KV_ID_VENDOR) {
- if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
- CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
- CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
- csr1212_keep_keyval(kv);
- vendor_name_kv = kv;
- }
- }
- break;
- }
- last_key_id = kv->key.id;
- }
-
- if (ne->vendor_name_kv) {
- kv = ne->vendor_name_kv;
- ne->vendor_name_kv = vendor_name_kv;
- csr1212_release_keyval(kv);
- } else if (vendor_name_kv) {
- ne->vendor_name_kv = vendor_name_kv;
- if (device_create_file(&ne->device,
- &dev_attr_ne_vendor_name_kv) != 0)
- HPSB_ERR("Failed to add sysfs attribute");
- }
-}
-
-#ifdef CONFIG_HOTPLUG
-
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct unit_directory *ud;
- int retval = 0;
- /* ieee1394:venNmoNspNverN */
- char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
-
- if (!dev)
- return -ENODEV;
-
- ud = container_of(dev, struct unit_directory, unit_dev);
-
- if (ud->ne->in_limbo || ud->ignore_driver)
- return -ENODEV;
-
-#define PUT_ENVP(fmt,val) \
-do { \
- retval = add_uevent_var(env, fmt, val); \
- if (retval) \
- return retval; \
-} while (0)
-
- PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);
- PUT_ENVP("MODEL_ID=%06x", ud->model_id);
- PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid);
- PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id);
- PUT_ENVP("VERSION=%06x", ud->version);
- snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X",
- ud->vendor_id,
- ud->model_id,
- ud->specifier_id,
- ud->version);
- PUT_ENVP("MODALIAS=%s", buf);
-
-#undef PUT_ENVP
-
- return 0;
-}
-
-#else
-
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- return -ENODEV;
-}
-
-#endif /* CONFIG_HOTPLUG */
-
-
-int __hpsb_register_protocol(struct hpsb_protocol_driver *drv,
- struct module *owner)
-{
- int error;
-
- drv->driver.bus = &ieee1394_bus_type;
- drv->driver.owner = owner;
- drv->driver.name = drv->name;
-
- /* This will cause a probe for devices */
- error = driver_register(&drv->driver);
- if (!error)
- nodemgr_create_drv_files(drv);
- return error;
-}
-
-void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver)
-{
- nodemgr_remove_drv_files(driver);
- /* This will subsequently disconnect all devices that our driver
- * is attached to. */
- driver_unregister(&driver->driver);
-}
-
-
-/*
- * This function updates nodes that were present on the bus before the
- * reset and still are after the reset. The nodeid and the config rom
- * may have changed, and the drivers managing this device must be
- * informed that this device just went through a bus reset, to allow
- * the to take whatever actions required.
- */
-static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr,
- nodeid_t nodeid, unsigned int generation)
-{
- if (ne->nodeid != nodeid) {
- HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT,
- NODE_BUS_ARGS(ne->host, ne->nodeid),
- NODE_BUS_ARGS(ne->host, nodeid));
- ne->nodeid = nodeid;
- }
-
- if (ne->busopt.generation != ((be32_to_cpu(csr->bus_info_data[2]) >> 4) & 0xf)) {
- kfree(ne->csr->private);
- csr1212_destroy_csr(ne->csr);
- ne->csr = csr;
-
- /* If the node's configrom generation has changed, we
- * unregister all the unit directories. */
- nodemgr_remove_uds(ne);
-
- nodemgr_update_bus_options(ne);
-
- /* Mark the node as new, so it gets re-probed */
- ne->needs_probe = true;
- } else {
- /* old cache is valid, so update its generation */
- struct nodemgr_csr_info *ci = ne->csr->private;
- ci->generation = generation;
- /* free the partially filled now unneeded new cache */
- kfree(csr->private);
- csr1212_destroy_csr(csr);
- }
-
- /* Finally, mark the node current */
- smp_wmb();
- ne->generation = generation;
-
- if (ne->in_limbo) {
- device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
- ne->in_limbo = false;
-
- HPSB_DEBUG("Node reactivated: "
- "ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
- NODE_BUS_ARGS(ne->host, ne->nodeid),
- (unsigned long long)ne->guid);
- }
-}
-
-static void nodemgr_node_scan_one(struct hpsb_host *host,
- nodeid_t nodeid, int generation)
-{
- struct node_entry *ne;
- octlet_t guid;
- struct csr1212_csr *csr;
- struct nodemgr_csr_info *ci;
- u8 *speed;
-
- ci = kmalloc(sizeof(*ci), GFP_KERNEL);
- kmemcheck_annotate_bitfield(ci, flags);
- if (!ci)
- return;
-
- ci->host = host;
- ci->nodeid = nodeid;
- ci->generation = generation;
-
- /* Prepare for speed probe which occurs when reading the ROM */
- speed = &(host->speed[NODEID_TO_NODE(nodeid)]);
- if (*speed > host->csr.lnk_spd)
- *speed = host->csr.lnk_spd;
- ci->speed_unverified = *speed > IEEE1394_SPEED_100;
-
- /* We need to detect when the ConfigROM's generation has changed,
- * so we only update the node's info when it needs to be. */
-
- csr = csr1212_create_csr(&nodemgr_csr_ops, 5 * sizeof(quadlet_t), ci);
- if (!csr || csr1212_parse_csr(csr) != CSR1212_SUCCESS) {
- HPSB_ERR("Error parsing configrom for node " NODE_BUS_FMT,
- NODE_BUS_ARGS(host, nodeid));
- if (csr)
- csr1212_destroy_csr(csr);
- kfree(ci);
- return;
- }
-
- if (csr->bus_info_data[1] != IEEE1394_BUSID_MAGIC) {
- /* This isn't a 1394 device, but we let it slide. There
- * was a report of a device with broken firmware which
- * reported '2394' instead of '1394', which is obviously a
- * mistake. One would hope that a non-1394 device never
- * gets connected to Firewire bus. If someone does, we
- * shouldn't be held responsible, so we'll allow it with a
- * warning. */
- HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]",
- NODE_BUS_ARGS(host, nodeid), csr->bus_info_data[1]);
- }
-
- guid = ((u64)be32_to_cpu(csr->bus_info_data[3]) << 32) | be32_to_cpu(csr->bus_info_data[4]);
- ne = find_entry_by_guid(guid);
-
- if (ne && ne->host != host && ne->in_limbo) {
- /* Must have moved this device from one host to another */
- nodemgr_remove_ne(ne);
- ne = NULL;
- }
-
- if (!ne)
- nodemgr_create_node(guid, csr, host, nodeid, generation);
- else
- nodemgr_update_node(ne, csr, nodeid, generation);
-}
-
-
-static void nodemgr_node_scan(struct hpsb_host *host, int generation)
-{
- int count;
- struct selfid *sid = (struct selfid *)host->topology_map;
- nodeid_t nodeid = LOCAL_BUS;
-
- /* Scan each node on the bus */
- for (count = host->selfid_count; count; count--, sid++) {
- if (sid->extended)
- continue;
-
- if (!sid->link_active) {
- nodeid++;
- continue;
- }
- nodemgr_node_scan_one(host, nodeid++, generation);
- }
-}
-
-static void nodemgr_pause_ne(struct node_entry *ne)
-{
- HPSB_DEBUG("Node paused: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
- NODE_BUS_ARGS(ne->host, ne->nodeid),
- (unsigned long long)ne->guid);
-
- ne->in_limbo = true;
- WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
-}
-
-static int update_pdrv(struct device *dev, void *data)
-{
- struct unit_directory *ud;
- struct device_driver *drv;
- struct hpsb_protocol_driver *pdrv;
- struct node_entry *ne = data;
- int error;
-
- ud = container_of(dev, struct unit_directory, unit_dev);
- if (ud->ne == ne) {
- drv = get_driver(ud->device.driver);
- if (drv) {
- error = 0;
- pdrv = container_of(drv, struct hpsb_protocol_driver,
- driver);
- if (pdrv->update) {
- device_lock(&ud->device);
- error = pdrv->update(ud);
- device_unlock(&ud->device);
- }
- if (error)
- device_release_driver(&ud->device);
- put_driver(drv);
- }
- }
-
- return 0;
-}
-
-static void nodemgr_update_pdrv(struct node_entry *ne)
-{
- class_for_each_device(&nodemgr_ud_class, NULL, ne, update_pdrv);
-}
-
-/* Write the BROADCAST_CHANNEL as per IEEE1394a 8.3.2.3.11 and 8.4.2.3. This
- * seems like an optional service but in the end it is practically mandatory
- * as a consequence of these clauses.
- *
- * Note that we cannot do a broadcast write to all nodes at once because some
- * pre-1394a devices would hang. */
-static void nodemgr_irm_write_bc(struct node_entry *ne, int generation)
-{
- const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL);
- quadlet_t bc_remote, bc_local;
- int error;
-
- if (!ne->host->is_irm || ne->generation != generation ||
- ne->nodeid == ne->host->node_id)
- return;
-
- bc_local = cpu_to_be32(ne->host->csr.broadcast_channel);
-
- /* Check if the register is implemented and 1394a compliant. */
- error = hpsb_read(ne->host, ne->nodeid, generation, bc_addr, &bc_remote,
- sizeof(bc_remote));
- if (!error && bc_remote & cpu_to_be32(0x80000000) &&
- bc_remote != bc_local)
- hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local));
-}
-
-
-static void nodemgr_probe_ne(struct hpsb_host *host, struct node_entry *ne,
- int generation)
-{
- struct device *dev;
-
- if (ne->host != host || ne->in_limbo)
- return;
-
- dev = get_device(&ne->device);
- if (!dev)
- return;
-
- nodemgr_irm_write_bc(ne, generation);
-
- /* If "needs_probe", then this is either a new or changed node we
- * rescan totally. If the generation matches for an existing node
- * (one that existed prior to the bus reset) we send update calls
- * down to the drivers. Otherwise, this is a dead node and we
- * suspend it. */
- if (ne->needs_probe)
- nodemgr_process_root_directory(ne);
- else if (ne->generation == generation)
- nodemgr_update_pdrv(ne);
- else
- nodemgr_pause_ne(ne);
-
- put_device(dev);
-}
-
-struct node_probe_parameter {
- struct hpsb_host *host;
- int generation;
- bool probe_now;
-};
-
-static int node_probe(struct device *dev, void *data)
-{
- struct node_probe_parameter *p = data;
- struct node_entry *ne;
-
- if (p->generation != get_hpsb_generation(p->host))
- return -EAGAIN;
-
- ne = container_of(dev, struct node_entry, node_dev);
- if (ne->needs_probe == p->probe_now)
- nodemgr_probe_ne(p->host, ne, p->generation);
- return 0;
-}
-
-static int nodemgr_node_probe(struct hpsb_host *host, int generation)
-{
- struct node_probe_parameter p;
-
- p.host = host;
- p.generation = generation;
- /*
- * Do some processing of the nodes we've probed. This pulls them
- * into the sysfs layer if needed, and can result in processing of
- * unit-directories, or just updating the node and it's
- * unit-directories.
- *
- * Run updates before probes. Usually, updates are time-critical
- * while probes are time-consuming.
- *
- * Meanwhile, another bus reset may have happened. In this case we
- * skip everything here and let the next bus scan handle it.
- * Otherwise we may prematurely remove nodes which are still there.
- */
- p.probe_now = false;
- if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0)
- return 0;
-
- p.probe_now = true;
- if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0)
- return 0;
- /*
- * Now let's tell the bus to rescan our devices. This may seem
- * like overhead, but the driver-model core will only scan a
- * device for a driver when either the device is added, or when a
- * new driver is added. A bus reset is a good reason to rescan
- * devices that were there before. For example, an sbp2 device
- * may become available for login, if the host that held it was
- * just removed.
- */
- if (bus_rescan_devices(&ieee1394_bus_type) != 0)
- HPSB_DEBUG("bus_rescan_devices had an error");
-
- return 1;
-}
-
-static int remove_nodes_in_limbo(struct device *dev, void *data)
-{
- struct node_entry *ne;
-
- if (dev->bus != &ieee1394_bus_type)
- return 0;
-
- ne = container_of(dev, struct node_entry, device);
- if (ne->in_limbo)
- nodemgr_remove_ne(ne);
-
- return 0;
-}
-
-static void nodemgr_remove_nodes_in_limbo(struct hpsb_host *host)
-{
- device_for_each_child(&host->device, NULL, remove_nodes_in_limbo);
-}
-
-static int nodemgr_send_resume_packet(struct hpsb_host *host)
-{
- struct hpsb_packet *packet;
- int error = -ENOMEM;
-
- packet = hpsb_make_phypacket(host,
- EXTPHYPACKET_TYPE_RESUME |
- NODEID_TO_NODE(host->node_id) << PHYPACKET_PORT_SHIFT);
- if (packet) {
- packet->no_waiter = 1;
- packet->generation = get_hpsb_generation(host);
- error = hpsb_send_packet(packet);
- }
- if (error)
- HPSB_WARN("fw-host%d: Failed to broadcast resume packet",
- host->id);
- return error;
-}
-
-/* Perform a few high-level IRM responsibilities. */
-static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles)
-{
- quadlet_t bc;
-
- /* if irm_id == -1 then there is no IRM on this bus */
- if (!host->is_irm || host->irm_id == (nodeid_t)-1)
- return 1;
-
- /* We are a 1394a-2000 compliant IRM. Set the validity bit. */
- host->csr.broadcast_channel |= 0x40000000;
-
- /* If there is no bus manager then we should set the root node's
- * force_root bit to promote bus stability per the 1394
- * spec. (8.4.2.6) */
- if (host->busmgr_id == 0xffff && host->node_count > 1)
- {
- u16 root_node = host->node_count - 1;
-
- /* get cycle master capability flag from root node */
- if (host->is_cycmst ||
- (!hpsb_read(host, LOCAL_BUS | root_node, get_hpsb_generation(host),
- (CSR_REGISTER_BASE + CSR_CONFIG_ROM + 2 * sizeof(quadlet_t)),
- &bc, sizeof(quadlet_t)) &&
- be32_to_cpu(bc) & 1 << CSR_CMC_SHIFT))
- hpsb_send_phy_config(host, root_node, -1);
- else {
- HPSB_DEBUG("The root node is not cycle master capable; "
- "selecting a new root node and resetting...");
-
- if (cycles >= 5) {
- /* Oh screw it! Just leave the bus as it is */
- HPSB_DEBUG("Stopping reset loop for IRM sanity");
- return 1;
- }
-
- hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);
- hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
-
- return 0;
- }
- }
-
- /* Some devices suspend their ports while being connected to an inactive
- * host adapter, i.e. if connected before the low-level driver is
- * loaded. They become visible either when physically unplugged and
- * replugged, or when receiving a resume packet. Send one once. */
- if (!host->resume_packet_sent && !nodemgr_send_resume_packet(host))
- host->resume_packet_sent = 1;
-
- return 1;
-}
-
-/* We need to ensure that if we are not the IRM, that the IRM node is capable of
- * everything we can do, otherwise issue a bus reset and try to become the IRM
- * ourselves. */
-static int nodemgr_check_irm_capability(struct hpsb_host *host, int cycles)
-{
- quadlet_t bc;
- int status;
-
- if (hpsb_disable_irm || host->is_irm)
- return 1;
-
- status = hpsb_read(host, LOCAL_BUS | (host->irm_id),
- get_hpsb_generation(host),
- (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
- &bc, sizeof(quadlet_t));
-
- if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {
- /* The current irm node does not have a valid BROADCAST_CHANNEL
- * register and we do, so reset the bus with force_root set */
- HPSB_DEBUG("Current remote IRM is not 1394a-2000 compliant, resetting...");
-
- if (cycles >= 5) {
- /* Oh screw it! Just leave the bus as it is */
- HPSB_DEBUG("Stopping reset loop for IRM sanity");
- return 1;
- }
-
- hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);
- hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
-
- return 0;
- }
-
- return 1;
-}
-
-static int nodemgr_host_thread(void *data)
-{
- struct hpsb_host *host = data;
- unsigned int g, generation = 0;
- int i, reset_cycles = 0;
-
- set_freezable();
- /* Setup our device-model entries */
- nodemgr_create_host_dev_files(host);
-
- for (;;) {
- /* Sleep until next bus reset */
- set_current_state(TASK_INTERRUPTIBLE);
- if (get_hpsb_generation(host) == generation &&
- !kthread_should_stop())
- schedule();
- __set_current_state(TASK_RUNNING);
-
- /* Thread may have been woken up to freeze or to exit */
- if (try_to_freeze())
- continue;
- if (kthread_should_stop())
- goto exit;
-
- /* Pause for 1/4 second in 1/16 second intervals,
- * to make sure things settle down. */
- g = get_hpsb_generation(host);
- for (i = 0; i < 4 ; i++) {
- msleep_interruptible(63);
- try_to_freeze();
- if (kthread_should_stop())
- goto exit;
-
- /* Now get the generation in which the node ID's we collect
- * are valid. During the bus scan we will use this generation
- * for the read transactions, so that if another reset occurs
- * during the scan the transactions will fail instead of
- * returning bogus data. */
- generation = get_hpsb_generation(host);
-
- /* If we get a reset before we are done waiting, then
- * start the waiting over again */
- if (generation != g)
- g = generation, i = 0;
- }
-
- if (!nodemgr_check_irm_capability(host, reset_cycles) ||
- !nodemgr_do_irm_duties(host, reset_cycles)) {
- reset_cycles++;
- continue;
- }
- reset_cycles = 0;
-
- /* Scan our nodes to get the bus options and create node
- * entries. This does not do the sysfs stuff, since that
- * would trigger uevents and such, which is a bad idea at
- * this point. */
- nodemgr_node_scan(host, generation);
-
- /* This actually does the full probe, with sysfs
- * registration. */
- if (!nodemgr_node_probe(host, generation))
- continue;
-
- /* Update some of our sysfs symlinks */
- nodemgr_update_host_dev_links(host);
-
- /* Sleep 3 seconds */
- for (i = 3000/200; i; i--) {
- msleep_interruptible(200);
- try_to_freeze();
- if (kthread_should_stop())
- goto exit;
-
- if (generation != get_hpsb_generation(host))
- break;
- }
- /* Remove nodes which are gone, unless a bus reset happened */
- if (!i)
- nodemgr_remove_nodes_in_limbo(host);
- }
-exit:
- HPSB_VERBOSE("NodeMgr: Exiting thread");
- return 0;
-}
-
-struct per_host_parameter {
- void *data;
- int (*cb)(struct hpsb_host *, void *);
-};
-
-static int per_host(struct device *dev, void *data)
-{
- struct hpsb_host *host;
- struct per_host_parameter *p = data;
-
- host = container_of(dev, struct hpsb_host, host_dev);
- return p->cb(host, p->data);
-}
-
-/**
- * nodemgr_for_each_host - call a function for each IEEE 1394 host
- * @data: an address to supply to the callback
- * @cb: function to call for each host
- *
- * Iterate the hosts, calling a given function with supplied data for each host.
- * If the callback fails on a host, i.e. if it returns a non-zero value, the
- * iteration is stopped.
- *
- * Return value: 0 on success, non-zero on failure (same as returned by last run
- * of the callback).
- */
-int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
-{
- struct per_host_parameter p;
-
- p.cb = cb;
- p.data = data;
- return class_for_each_device(&hpsb_host_class, NULL, &p, per_host);
-}
-
-/* The following two convenience functions use a struct node_entry
- * for addressing a node on the bus. They are intended for use by any
- * process context, not just the nodemgr thread, so we need to be a
- * little careful when reading out the node ID and generation. The
- * thing that can go wrong is that we get the node ID, then a bus
- * reset occurs, and then we read the generation. The node ID is
- * possibly invalid, but the generation is current, and we end up
- * sending a packet to a the wrong node.
- *
- * The solution is to make sure we read the generation first, so that
- * if a reset occurs in the process, we end up with a stale generation
- * and the transactions will fail instead of silently using wrong node
- * ID's.
- */
-
-/**
- * hpsb_node_fill_packet - fill some destination information into a packet
- * @ne: destination node
- * @packet: packet to fill in
- *
- * This will fill in the given, pre-initialised hpsb_packet with the current
- * information from the node entry (host, node ID, bus generation number).
- */
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
-{
- packet->host = ne->host;
- packet->generation = ne->generation;
- smp_rmb();
- packet->node_id = ne->nodeid;
-}
-
-int hpsb_node_write(struct node_entry *ne, u64 addr,
- quadlet_t *buffer, size_t length)
-{
- unsigned int generation = ne->generation;
-
- smp_rmb();
- return hpsb_write(ne->host, ne->nodeid, generation,
- addr, buffer, length);
-}
-
-static void nodemgr_add_host(struct hpsb_host *host)
-{
- struct host_info *hi;
-
- hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi));
- if (!hi) {
- HPSB_ERR("NodeMgr: out of memory in add host");
- return;
- }
- hi->host = host;
- hi->thread = kthread_run(nodemgr_host_thread, host, "knodemgrd_%d",
- host->id);
- if (IS_ERR(hi->thread)) {
- HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id);
- hpsb_destroy_hostinfo(&nodemgr_highlevel, host);
- }
-}
-
-static void nodemgr_host_reset(struct hpsb_host *host)
-{
- struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
-
- if (hi) {
- HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id);
- wake_up_process(hi->thread);
- }
-}
-
-static void nodemgr_remove_host(struct hpsb_host *host)
-{
- struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
-
- if (hi) {
- kthread_stop(hi->thread);
- nodemgr_remove_host_dev(&host->device);
- }
-}
-
-static struct hpsb_highlevel nodemgr_highlevel = {
- .name = "Node manager",
- .add_host = nodemgr_add_host,
- .host_reset = nodemgr_host_reset,
- .remove_host = nodemgr_remove_host,
-};
-
-int init_ieee1394_nodemgr(void)
-{
- int error;
-
- error = class_register(&nodemgr_ne_class);
- if (error)
- goto fail_ne;
- error = class_register(&nodemgr_ud_class);
- if (error)
- goto fail_ud;
- error = driver_register(&nodemgr_mid_layer_driver);
- if (error)
- goto fail_ml;
- /* This driver is not used if nodemgr is off (disable_nodemgr=1). */
- nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;
-
- hpsb_register_highlevel(&nodemgr_highlevel);
- return 0;
-
-fail_ml:
- class_unregister(&nodemgr_ud_class);
-fail_ud:
- class_unregister(&nodemgr_ne_class);
-fail_ne:
- return error;
-}
-
-void cleanup_ieee1394_nodemgr(void)
-{
- hpsb_unregister_highlevel(&nodemgr_highlevel);
- driver_unregister(&nodemgr_mid_layer_driver);
- class_unregister(&nodemgr_ud_class);
- class_unregister(&nodemgr_ne_class);
-}
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
deleted file mode 100644
index 749b271d3107..000000000000
--- a/drivers/ieee1394/nodemgr.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2000 Andreas E. Bombe
- * 2001 Ben Collins <bcollins@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _IEEE1394_NODEMGR_H
-#define _IEEE1394_NODEMGR_H
-
-#include <linux/device.h>
-#include <asm/system.h>
-#include <asm/types.h>
-
-#include "ieee1394_core.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-
-struct csr1212_csr;
-struct csr1212_keyval;
-struct hpsb_host;
-struct ieee1394_device_id;
-
-/* This is the start of a Node entry structure. It should be a stable API
- * for which to gather info from the Node Manager about devices attached
- * to the bus. */
-struct bus_options {
- u8 irmc; /* Iso Resource Manager Capable */
- u8 cmc; /* Cycle Master Capable */
- u8 isc; /* Iso Capable */
- u8 bmc; /* Bus Master Capable */
- u8 pmc; /* Power Manager Capable (PNP spec) */
- u8 cyc_clk_acc; /* Cycle clock accuracy */
- u8 max_rom; /* Maximum block read supported in the CSR */
- u8 generation; /* Incremented when configrom changes */
- u8 lnkspd; /* Link speed */
- u16 max_rec; /* Maximum packet size node can receive */
-};
-
-#define UNIT_DIRECTORY_VENDOR_ID 0x01
-#define UNIT_DIRECTORY_MODEL_ID 0x02
-#define UNIT_DIRECTORY_SPECIFIER_ID 0x04
-#define UNIT_DIRECTORY_VERSION 0x08
-#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY 0x10
-#define UNIT_DIRECTORY_LUN_DIRECTORY 0x20
-#define UNIT_DIRECTORY_HAS_LUN 0x40
-
-/*
- * A unit directory corresponds to a protocol supported by the
- * node. If a node supports eg. IP/1394 and AV/C, its config rom has a
- * unit directory for each of these protocols.
- */
-struct unit_directory {
- struct node_entry *ne; /* The node which this directory belongs to */
- octlet_t address; /* Address of the unit directory on the node */
- u8 flags; /* Indicates which entries were read */
-
- quadlet_t vendor_id;
- struct csr1212_keyval *vendor_name_kv;
-
- quadlet_t model_id;
- struct csr1212_keyval *model_name_kv;
- quadlet_t specifier_id;
- quadlet_t version;
- quadlet_t directory_id;
-
- unsigned int id;
-
- int ignore_driver;
-
- int length; /* Number of quadlets */
-
- struct device device;
- struct device unit_dev;
-
- struct csr1212_keyval *ud_kv;
- u32 lun; /* logical unit number immediate value */
-};
-
-struct node_entry {
- u64 guid; /* GUID of this node */
- u32 guid_vendor_id; /* Top 24bits of guid */
-
- struct hpsb_host *host; /* Host this node is attached to */
- nodeid_t nodeid; /* NodeID */
- struct bus_options busopt; /* Bus Options */
- bool needs_probe;
- unsigned int generation; /* Synced with hpsb generation */
-
- /* The following is read from the config rom */
- u32 vendor_id;
- struct csr1212_keyval *vendor_name_kv;
-
- u32 capabilities;
-
- struct device device;
- struct device node_dev;
-
- /* Means this node is not attached anymore */
- bool in_limbo;
-
- struct csr1212_csr *csr;
-};
-
-struct hpsb_protocol_driver {
- /* The name of the driver, e.g. SBP2 or IP1394 */
- const char *name;
-
- /*
- * The device id table describing the protocols and/or devices
- * supported by this driver. This is used by the nodemgr to
- * decide if a driver could support a given node, but the
- * probe function below can implement further protocol
- * dependent or vendor dependent checking.
- */
- const struct ieee1394_device_id *id_table;
-
- /*
- * The update function is called when the node has just
- * survived a bus reset, i.e. it is still present on the bus.
- * However, it may be necessary to reestablish the connection
- * or login into the node again, depending on the protocol. If the
- * probe fails (returns non-zero), we unbind the driver from this
- * device.
- */
- int (*update)(struct unit_directory *ud);
-
- /* Our LDM structure */
- struct device_driver driver;
-};
-
-int __hpsb_register_protocol(struct hpsb_protocol_driver *, struct module *);
-static inline int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
-{
- return __hpsb_register_protocol(driver, THIS_MODULE);
-}
-
-void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver);
-
-static inline int hpsb_node_entry_valid(struct node_entry *ne)
-{
- return ne->generation == get_hpsb_generation(ne->host);
-}
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet);
-int hpsb_node_write(struct node_entry *ne, u64 addr,
- quadlet_t *buffer, size_t length);
-static inline int hpsb_node_read(struct node_entry *ne, u64 addr,
- quadlet_t *buffer, size_t length)
-{
- unsigned int g = ne->generation;
-
- smp_rmb();
- return hpsb_read(ne->host, ne->nodeid, g, addr, buffer, length);
-}
-static inline int hpsb_node_lock(struct node_entry *ne, u64 addr, int extcode,
- quadlet_t *buffer, quadlet_t arg)
-{
- unsigned int g = ne->generation;
-
- smp_rmb();
- return hpsb_lock(ne->host, ne->nodeid, g, addr, extcode, buffer, arg);
-}
-int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *));
-
-int init_ieee1394_nodemgr(void);
-void cleanup_ieee1394_nodemgr(void);
-
-/* The template for a host device */
-extern struct device nodemgr_dev_template_host;
-
-/* Bus attributes we export */
-extern struct bus_attribute *const fw_bus_attrs[];
-
-#endif /* _IEEE1394_NODEMGR_H */
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
deleted file mode 100644
index 50815022cff1..000000000000
--- a/drivers/ieee1394/ohci1394.c
+++ /dev/null
@@ -1,3590 +0,0 @@
-/*
- * ohci1394.c - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Gord Peters <GordPeters@smarttech.com>
- * 2001 Ben Collins <bcollins@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * Things known to be working:
- * . Async Request Transmit
- * . Async Response Receive
- * . Async Request Receive
- * . Async Response Transmit
- * . Iso Receive
- * . DMA mmap for iso receive
- * . Config ROM generation
- *
- * Things implemented, but still in test phase:
- * . Iso Transmit
- * . Async Stream Packets Transmit (Receive done via Iso interface)
- *
- * Things not implemented:
- * . DMA error recovery
- *
- * Known bugs:
- * . devctl BUS_RESET arg confusion (reset type or root holdoff?)
- * added LONG_RESET_ROOT and SHORT_RESET_ROOT for root holdoff --kk
- */
-
-/*
- * Acknowledgments:
- *
- * Adam J Richter <adam@yggdrasil.com>
- * . Use of pci_class to find device
- *
- * Emilie Chung <emilie.chung@axis.com>
- * . Tip on Async Request Filter
- *
- * Pascal Drolet <pascal.drolet@informission.ca>
- * . Various tips for optimization and functionnalities
- *
- * Robert Ficklin <rficklin@westengineering.com>
- * . Loop in irq_handler
- *
- * James Goodwin <jamesg@Filanet.com>
- * . Various tips on initialization, self-id reception, etc.
- *
- * Albrecht Dress <ad@mpifr-bonn.mpg.de>
- * . Apple PowerBook detection
- *
- * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
- * . Reset the board properly before leaving + misc cleanups
- *
- * Leon van Stuivenberg <leonvs@iae.nl>
- * . Bug fixes
- *
- * Ben Collins <bcollins@debian.org>
- * . Working big-endian support
- * . Updated to 2.4.x module scheme (PCI aswell)
- * . Config ROM generation
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * . Reworked code for initiating bus resets
- * (long, short, with or without hold-off)
- *
- * Nandu Santhi <contactnandu@users.sourceforge.net>
- * . Added support for nVidia nForce2 onboard Firewire chipset
- *
- */
-
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/uaccess.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/irq.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-
-#ifdef CONFIG_PPC_PMAC
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#endif
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "dma.h"
-#include "iso.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "ohci1394.h"
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define OHCI1394_DEBUG
-#endif
-
-#ifdef DBGMSG
-#undef DBGMSG
-#endif
-
-#ifdef OHCI1394_DEBUG
-#define DBGMSG(fmt, args...) \
-printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
-#else
-#define DBGMSG(fmt, args...) do {} while (0)
-#endif
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) \
-printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
-
-/* print card specific information */
-#define PRINT(level, fmt, args...) \
-printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
-
-/* Module Parameters */
-static int phys_dma = 1;
-module_param(phys_dma, int, 0444);
-MODULE_PARM_DESC(phys_dma, "Enable physical DMA (default = 1).");
-
-static void dma_trm_tasklet(unsigned long data);
-static void dma_trm_reset(struct dma_trm_ctx *d);
-
-static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int buf_size, int split_buf_size, int context_base);
-static void free_dma_rcv_ctx(struct dma_rcv_ctx *d);
-
-static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int context_base);
-
-static void ohci1394_pci_remove(struct pci_dev *pdev);
-
-#ifndef __LITTLE_ENDIAN
-static const size_t hdr_sizes[] = {
- 3, /* TCODE_WRITEQ */
- 4, /* TCODE_WRITEB */
- 3, /* TCODE_WRITE_RESPONSE */
- 0, /* reserved */
- 3, /* TCODE_READQ */
- 4, /* TCODE_READB */
- 3, /* TCODE_READQ_RESPONSE */
- 4, /* TCODE_READB_RESPONSE */
- 1, /* TCODE_CYCLE_START */
- 4, /* TCODE_LOCK_REQUEST */
- 2, /* TCODE_ISO_DATA */
- 4, /* TCODE_LOCK_RESPONSE */
- /* rest is reserved or link-internal */
-};
-
-static inline void header_le32_to_cpu(quadlet_t *data, unsigned char tcode)
-{
- size_t size;
-
- if (unlikely(tcode >= ARRAY_SIZE(hdr_sizes)))
- return;
-
- size = hdr_sizes[tcode];
- while (size--)
- data[size] = le32_to_cpu(data[size]);
-}
-#else
-#define header_le32_to_cpu(w,x) do {} while (0)
-#endif /* !LITTLE_ENDIAN */
-
-/***********************************
- * IEEE-1394 functionality section *
- ***********************************/
-
-static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr)
-{
- int i;
- unsigned long flags;
- quadlet_t r;
-
- spin_lock_irqsave (&ohci->phy_reg_lock, flags);
-
- reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
-
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
- break;
-
- mdelay(1);
- }
-
- r = reg_read(ohci, OHCI1394_PhyControl);
-
- if (i >= OHCI_LOOP_COUNT)
- PRINT (KERN_ERR, "Get PHY Reg timeout [0x%08x/0x%08x/%d]",
- r, r & 0x80000000, i);
-
- spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
-
- return (r & 0x00ff0000) >> 16;
-}
-
-static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
-{
- int i;
- unsigned long flags;
- u32 r = 0;
-
- spin_lock_irqsave (&ohci->phy_reg_lock, flags);
-
- reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
-
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- r = reg_read(ohci, OHCI1394_PhyControl);
- if (!(r & 0x00004000))
- break;
-
- mdelay(1);
- }
-
- if (i == OHCI_LOOP_COUNT)
- PRINT (KERN_ERR, "Set PHY Reg timeout [0x%08x/0x%08x/%d]",
- r, r & 0x00004000, i);
-
- spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
-
- return;
-}
-
-/* Or's our value into the current value */
-static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data)
-{
- u8 old;
-
- old = get_phy_reg (ohci, addr);
- old |= data;
- set_phy_reg (ohci, addr, old);
-
- return;
-}
-
-static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
- int phyid, int isroot)
-{
- quadlet_t *q = ohci->selfid_buf_cpu;
- quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount);
- size_t size;
- quadlet_t q0, q1;
-
- /* Check status of self-id reception */
-
- if (ohci->selfid_swap)
- q0 = le32_to_cpu(q[0]);
- else
- q0 = q[0];
-
- if ((self_id_count & 0x80000000) ||
- ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) {
- PRINT(KERN_ERR,
- "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)",
- self_id_count, q0, ohci->self_id_errors);
-
- /* Tip by James Goodwin <jamesg@Filanet.com>:
- * We had an error, generate another bus reset in response. */
- if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) {
- set_phy_reg_mask (ohci, 1, 0x40);
- ohci->self_id_errors++;
- } else {
- PRINT(KERN_ERR,
- "Too many errors on SelfID error reception, giving up!");
- }
- return;
- }
-
- /* SelfID Ok, reset error counter. */
- ohci->self_id_errors = 0;
-
- size = ((self_id_count & 0x00001FFC) >> 2) - 1;
- q++;
-
- while (size > 0) {
- if (ohci->selfid_swap) {
- q0 = le32_to_cpu(q[0]);
- q1 = le32_to_cpu(q[1]);
- } else {
- q0 = q[0];
- q1 = q[1];
- }
-
- if (q0 == ~q1) {
- DBGMSG ("SelfID packet 0x%x received", q0);
- hpsb_selfid_received(host, cpu_to_be32(q0));
- if (((q0 & 0x3f000000) >> 24) == phyid)
- DBGMSG ("SelfID for this node is 0x%08x", q0);
- } else {
- PRINT(KERN_ERR,
- "SelfID is inconsistent [0x%08x/0x%08x]", q0, q1);
- }
- q += 2;
- size -= 2;
- }
-
- DBGMSG("SelfID complete");
-
- return;
-}
-
-static void ohci_soft_reset(struct ti_ohci *ohci) {
- int i;
-
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
-
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- if (!(reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset))
- break;
- mdelay(1);
- }
- DBGMSG ("Soft reset finished");
-}
-
-
-/* Generate the dma receive prgs and start the context */
-static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq)
-{
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- int i;
-
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
- for (i=0; i<d->num_desc; i++) {
- u32 c;
-
- c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH;
- if (generate_irq)
- c |= DMA_CTL_IRQ;
-
- d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size);
-
- /* End of descriptor list? */
- if (i + 1 < d->num_desc) {
- d->prg_cpu[i]->branchAddress =
- cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1);
- } else {
- d->prg_cpu[i]->branchAddress =
- cpu_to_le32((d->prg_bus[0] & 0xfffffff0));
- }
-
- d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]);
- d->prg_cpu[i]->status = cpu_to_le32(d->buf_size);
- }
-
- d->buf_ind = 0;
- d->buf_offset = 0;
-
- if (d->type == DMA_CTX_ISO) {
- /* Clear contextControl */
- reg_write(ohci, d->ctrlClear, 0xffffffff);
-
- /* Set bufferFill, isochHeader, multichannel for IR context */
- reg_write(ohci, d->ctrlSet, 0xd0000000);
-
- /* Set the context match register to match on all tags */
- reg_write(ohci, d->ctxtMatch, 0xf0000000);
-
- /* Clear the multi channel mask high and low registers */
- reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
-
- /* Set up isoRecvIntMask to generate interrupts */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << d->ctx);
- }
-
- /* Tell the controller where the first AR program is */
- reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1);
-
- /* Run context */
- reg_write(ohci, d->ctrlSet, 0x00008000);
-
- DBGMSG("Receive DMA ctx=%d initialized", d->ctx);
-}
-
-/* Initialize the dma transmit context */
-static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
-{
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-
- /* Stop the context */
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
- d->prg_ind = 0;
- d->sent_ind = 0;
- d->free_prgs = d->num_desc;
- d->branchAddrPtr = NULL;
- INIT_LIST_HEAD(&d->fifo_list);
- INIT_LIST_HEAD(&d->pending_list);
-
- if (d->type == DMA_CTX_ISO) {
- /* enable interrupts */
- reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << d->ctx);
- }
-
- DBGMSG("Transmit DMA ctx=%d initialized", d->ctx);
-}
-
-/* Count the number of available iso contexts */
-static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
-{
- u32 tmp;
-
- reg_write(ohci, reg, 0xffffffff);
- tmp = reg_read(ohci, reg);
-
- DBGMSG("Iso contexts reg: %08x implemented: %08x", reg, tmp);
-
- /* Count the number of contexts */
- return hweight32(tmp);
-}
-
-/* Global initialization */
-static void ohci_initialize(struct ti_ohci *ohci)
-{
- quadlet_t buf;
- int num_ports, i;
-
- spin_lock_init(&ohci->phy_reg_lock);
-
- /* Put some defaults to these undefined bus options */
- buf = reg_read(ohci, OHCI1394_BusOptions);
- buf |= 0x60000000; /* Enable CMC and ISC */
- if (hpsb_disable_irm)
- buf &= ~0x80000000;
- else
- buf |= 0x80000000; /* Enable IRMC */
- buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
- buf &= ~0x18000000; /* Disable PMC and BMC */
- reg_write(ohci, OHCI1394_BusOptions, buf);
-
- /* Set the bus number */
- reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
-
- /* Enable posted writes */
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable);
-
- /* Clear link control register */
- reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-
- /* Enable cycle timer and cycle master and set the IRM
- * contender bit in our self ID packets if appropriate. */
- reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_CycleTimerEnable |
- OHCI1394_LinkControl_CycleMaster);
- i = get_phy_reg(ohci, 4) | PHY_04_LCTRL;
- if (hpsb_disable_irm)
- i &= ~PHY_04_CONTENDER;
- else
- i |= PHY_04_CONTENDER;
- set_phy_reg(ohci, 4, i);
-
- /* Set up self-id dma buffer */
- reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
-
- /* enable self-id */
- reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID);
-
- /* Set the Config ROM mapping register */
- reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
-
- /* Now get our max packet size */
- ohci->max_packet_size =
- 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
-
- /* Clear the interrupt mask */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-
- /* Clear the interrupt mask */
- reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
-
- /* Initialize AR dma */
- initialize_dma_rcv_ctx(&ohci->ar_req_context, 0);
- initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0);
-
- /* Initialize AT dma */
- initialize_dma_trm_ctx(&ohci->at_req_context);
- initialize_dma_trm_ctx(&ohci->at_resp_context);
-
- /* Accept AR requests from all nodes */
- reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
-
- /* Set the address range of the physical response unit.
- * Most controllers do not implement it as a writable register though.
- * They will keep a hardwired offset of 0x00010000 and show 0x0 as
- * register content.
- * To actually enable physical responses is the job of our interrupt
- * handler which programs the physical request filter. */
- reg_write(ohci, OHCI1394_PhyUpperBound,
- OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED >> 16);
-
- DBGMSG("physUpperBoundOffset=%08x",
- reg_read(ohci, OHCI1394_PhyUpperBound));
-
- /* Specify AT retries */
- reg_write(ohci, OHCI1394_ATRetries,
- OHCI1394_MAX_AT_REQ_RETRIES |
- (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
- (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
-
- /* We don't want hardware swapping */
- reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
-
- /* Enable interrupts */
- reg_write(ohci, OHCI1394_IntMaskSet,
- OHCI1394_unrecoverableError |
- OHCI1394_masterIntEnable |
- OHCI1394_busReset |
- OHCI1394_selfIDComplete |
- OHCI1394_RSPkt |
- OHCI1394_RQPkt |
- OHCI1394_respTxComplete |
- OHCI1394_reqTxComplete |
- OHCI1394_isochRx |
- OHCI1394_isochTx |
- OHCI1394_postedWriteErr |
- OHCI1394_cycleTooLong |
- OHCI1394_cycleInconsistent);
-
- /* Enable link */
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
-
- buf = reg_read(ohci, OHCI1394_Version);
- PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%d] "
- "MMIO=[%llx-%llx] Max Packet=[%d] IR/IT contexts=[%d/%d]",
- ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
- ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
- (unsigned long long)pci_resource_start(ohci->dev, 0),
- (unsigned long long)pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
- ohci->max_packet_size,
- ohci->nb_iso_rcv_ctx, ohci->nb_iso_xmit_ctx);
-
- /* Check all of our ports to make sure that if anything is
- * connected, we enable that port. */
- num_ports = get_phy_reg(ohci, 2) & 0xf;
- for (i = 0; i < num_ports; i++) {
- unsigned int status;
-
- set_phy_reg(ohci, 7, i);
- status = get_phy_reg(ohci, 8);
-
- if (status & 0x20)
- set_phy_reg(ohci, 8, status & ~1);
- }
-
- /* Serial EEPROM Sanity check. */
- if ((ohci->max_packet_size < 512) ||
- (ohci->max_packet_size > 4096)) {
- /* Serial EEPROM contents are suspect, set a sane max packet
- * size and print the raw contents for bug reports if verbose
- * debug is enabled. */
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- int i;
-#endif
-
- PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, "
- "attempting to set max_packet_size to 512 bytes");
- reg_write(ohci, OHCI1394_BusOptions,
- (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002);
- ohci->max_packet_size = 512;
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- PRINT(KERN_DEBUG, " EEPROM Present: %d",
- (reg_read(ohci, OHCI1394_Version) >> 24) & 0x1);
- reg_write(ohci, OHCI1394_GUID_ROM, 0x80000000);
-
- for (i = 0;
- ((i < 1000) &&
- (reg_read(ohci, OHCI1394_GUID_ROM) & 0x80000000)); i++)
- udelay(10);
-
- for (i = 0; i < 0x20; i++) {
- reg_write(ohci, OHCI1394_GUID_ROM, 0x02000000);
- PRINT(KERN_DEBUG, " EEPROM %02x: %02x", i,
- (reg_read(ohci, OHCI1394_GUID_ROM) >> 16) & 0xff);
- }
-#endif
- }
-}
-
-/*
- * Insert a packet in the DMA fifo and generate the DMA prg
- * FIXME: rewrite the program in order to accept packets crossing
- * page boundaries.
- * check also that a single dma descriptor doesn't cross a
- * page boundary.
- */
-static void insert_packet(struct ti_ohci *ohci,
- struct dma_trm_ctx *d, struct hpsb_packet *packet)
-{
- u32 cycleTimer;
- int idx = d->prg_ind;
-
- DBGMSG("Inserting packet for node " NODE_BUS_FMT
- ", tlabel=%d, tcode=0x%x, speed=%d",
- NODE_BUS_ARGS(ohci->host, packet->node_id), packet->tlabel,
- packet->tcode, packet->speed_code);
-
- d->prg_cpu[idx]->begin.address = 0;
- d->prg_cpu[idx]->begin.branchAddress = 0;
-
- if (d->type == DMA_CTX_ASYNC_RESP) {
- /*
- * For response packets, we need to put a timeout value in
- * the 16 lower bits of the status... let's try 1 sec timeout
- */
- cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- d->prg_cpu[idx]->begin.status = cpu_to_le32(
- (((((cycleTimer>>25)&0x7)+1)&0x7)<<13) |
- ((cycleTimer&0x01fff000)>>12));
-
- DBGMSG("cycleTimer: %08x timeStamp: %08x",
- cycleTimer, d->prg_cpu[idx]->begin.status);
- } else
- d->prg_cpu[idx]->begin.status = 0;
-
- if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) {
-
- if (packet->type == hpsb_raw) {
- d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4);
- d->prg_cpu[idx]->data[1] = cpu_to_le32(packet->header[0]);
- d->prg_cpu[idx]->data[2] = cpu_to_le32(packet->header[1]);
- } else {
- d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
- (packet->header[0] & 0xFFFF);
-
- if (packet->tcode == TCODE_ISO_DATA) {
- /* Sending an async stream packet */
- d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
- } else {
- /* Sending a normal async request or response */
- d->prg_cpu[idx]->data[1] =
- (packet->header[1] & 0xFFFF) |
- (packet->header[0] & 0xFFFF0000);
- d->prg_cpu[idx]->data[2] = packet->header[2];
- d->prg_cpu[idx]->data[3] = packet->header[3];
- }
- header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
- }
-
- if (packet->data_size) { /* block transmit */
- if (packet->tcode == TCODE_STREAM_DATA){
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 0x8);
- } else {
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 0x10);
- }
- d->prg_cpu[idx]->end.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- packet->data_size);
- /*
- * Check that the packet data buffer
- * does not cross a page boundary.
- *
- * XXX Fix this some day. eth1394 seems to trigger
- * it, but ignoring it doesn't seem to cause a
- * problem.
- */
-#if 0
- if (cross_bound((unsigned long)packet->data,
- packet->data_size)>0) {
- /* FIXME: do something about it */
- PRINT(KERN_ERR,
- "%s: packet data addr: %p size %Zd bytes "
- "cross page boundary", __func__,
- packet->data, packet->data_size);
- }
-#endif
- d->prg_cpu[idx]->end.address = cpu_to_le32(
- pci_map_single(ohci->dev, packet->data,
- packet->data_size,
- PCI_DMA_TODEVICE));
-
- d->prg_cpu[idx]->end.branchAddress = 0;
- d->prg_cpu[idx]->end.status = 0;
- if (d->branchAddrPtr)
- *(d->branchAddrPtr) =
- cpu_to_le32(d->prg_bus[idx] | 0x3);
- d->branchAddrPtr =
- &(d->prg_cpu[idx]->end.branchAddress);
- } else { /* quadlet transmit */
- if (packet->type == hpsb_raw)
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_IMMEDIATE |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- (packet->header_size + 4));
- else
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_IMMEDIATE |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- packet->header_size);
-
- if (d->branchAddrPtr)
- *(d->branchAddrPtr) =
- cpu_to_le32(d->prg_bus[idx] | 0x2);
- d->branchAddrPtr =
- &(d->prg_cpu[idx]->begin.branchAddress);
- }
-
- } else { /* iso packet */
- d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
- (packet->header[0] & 0xFFFF);
- d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
- header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
-
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 0x8);
- d->prg_cpu[idx]->end.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_UPDATE |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- packet->data_size);
- d->prg_cpu[idx]->end.address = cpu_to_le32(
- pci_map_single(ohci->dev, packet->data,
- packet->data_size, PCI_DMA_TODEVICE));
-
- d->prg_cpu[idx]->end.branchAddress = 0;
- d->prg_cpu[idx]->end.status = 0;
- DBGMSG("Iso xmit context info: header[%08x %08x]\n"
- " begin=%08x %08x %08x %08x\n"
- " %08x %08x %08x %08x\n"
- " end =%08x %08x %08x %08x",
- d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1],
- d->prg_cpu[idx]->begin.control,
- d->prg_cpu[idx]->begin.address,
- d->prg_cpu[idx]->begin.branchAddress,
- d->prg_cpu[idx]->begin.status,
- d->prg_cpu[idx]->data[0],
- d->prg_cpu[idx]->data[1],
- d->prg_cpu[idx]->data[2],
- d->prg_cpu[idx]->data[3],
- d->prg_cpu[idx]->end.control,
- d->prg_cpu[idx]->end.address,
- d->prg_cpu[idx]->end.branchAddress,
- d->prg_cpu[idx]->end.status);
- if (d->branchAddrPtr)
- *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3);
- d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);
- }
- d->free_prgs--;
-
- /* queue the packet in the appropriate context queue */
- list_add_tail(&packet->driver_list, &d->fifo_list);
- d->prg_ind = (d->prg_ind + 1) % d->num_desc;
-}
-
-/*
- * This function fills the FIFO with the (eventual) pending packets
- * and runs or wakes up the DMA prg if necessary.
- *
- * The function MUST be called with the d->lock held.
- */
-static void dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d)
-{
- struct hpsb_packet *packet, *ptmp;
- int idx = d->prg_ind;
- int z = 0;
-
- /* insert the packets into the dma fifo */
- list_for_each_entry_safe(packet, ptmp, &d->pending_list, driver_list) {
- if (!d->free_prgs)
- break;
-
- /* For the first packet only */
- if (!z)
- z = (packet->data_size) ? 3 : 2;
-
- /* Insert the packet */
- list_del_init(&packet->driver_list);
- insert_packet(ohci, d, packet);
- }
-
- /* Nothing must have been done, either no free_prgs or no packets */
- if (z == 0)
- return;
-
- /* Is the context running ? (should be unless it is
- the first packet to be sent in this context) */
- if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
- u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
-
- DBGMSG("Starting transmit DMA ctx=%d",d->ctx);
- reg_write(ohci, d->cmdPtr, d->prg_bus[idx] | z);
-
- /* Check that the node id is valid, and not 63 */
- if (!(nodeId & 0x80000000) || (nodeId & 0x3f) == 63)
- PRINT(KERN_ERR, "Running dma failed because Node ID is not valid");
- else
- reg_write(ohci, d->ctrlSet, 0x8000);
- } else {
- /* Wake up the dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400))
- DBGMSG("Waking transmit DMA ctx=%d",d->ctx);
-
- /* do this always, to avoid race condition */
- reg_write(ohci, d->ctrlSet, 0x1000);
- }
-
- return;
-}
-
-/* Transmission of an async or iso packet */
-static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
-{
- struct ti_ohci *ohci = host->hostdata;
- struct dma_trm_ctx *d;
- unsigned long flags;
-
- if (packet->data_size > ohci->max_packet_size) {
- PRINT(KERN_ERR,
- "Transmit packet size %Zd is too big",
- packet->data_size);
- return -EOVERFLOW;
- }
-
- if (packet->type == hpsb_raw)
- d = &ohci->at_req_context;
- else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA))
- d = &ohci->at_resp_context;
- else
- d = &ohci->at_req_context;
-
- spin_lock_irqsave(&d->lock,flags);
-
- list_add_tail(&packet->driver_list, &d->pending_list);
-
- dma_trm_flush(ohci, d);
-
- spin_unlock_irqrestore(&d->lock,flags);
-
- return 0;
-}
-
-static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
-{
- struct ti_ohci *ohci = host->hostdata;
- int retval = 0, phy_reg;
-
- switch (cmd) {
- case RESET_BUS:
- switch (arg) {
- case SHORT_RESET:
- phy_reg = get_phy_reg(ohci, 5);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
- break;
- case LONG_RESET:
- phy_reg = get_phy_reg(ohci, 1);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 1, phy_reg); /* set IBR */
- break;
- case SHORT_RESET_NO_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- if (phy_reg & 0x80) {
- phy_reg &= ~0x80;
- set_phy_reg(ohci, 1, phy_reg); /* clear RHB */
- }
-
- phy_reg = get_phy_reg(ohci, 5);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
- break;
- case LONG_RESET_NO_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- phy_reg &= ~0x80;
- phy_reg |= 0x40;
- set_phy_reg(ohci, 1, phy_reg); /* clear RHB, set IBR */
- break;
- case SHORT_RESET_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- if (!(phy_reg & 0x80)) {
- phy_reg |= 0x80;
- set_phy_reg(ohci, 1, phy_reg); /* set RHB */
- }
-
- phy_reg = get_phy_reg(ohci, 5);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
- break;
- case LONG_RESET_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- phy_reg |= 0xc0;
- set_phy_reg(ohci, 1, phy_reg); /* set RHB and IBR */
- break;
- default:
- retval = -1;
- }
- break;
-
- case GET_CYCLE_COUNTER:
- retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- break;
-
- case SET_CYCLE_COUNTER:
- reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg);
- break;
-
- case SET_BUS_ID:
- PRINT(KERN_ERR, "devctl command SET_BUS_ID err");
- break;
-
- case ACT_CYCLE_MASTER:
- if (arg) {
- /* check if we are root and other nodes are present */
- u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
- if ((nodeId & (1<<30)) && (nodeId & 0x3f)) {
- /*
- * enable cycleTimer, cycleMaster
- */
- DBGMSG("Cycle master enabled");
- reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_CycleTimerEnable |
- OHCI1394_LinkControl_CycleMaster);
- }
- } else {
- /* disable cycleTimer, cycleMaster, cycleSource */
- reg_write(ohci, OHCI1394_LinkControlClear,
- OHCI1394_LinkControl_CycleTimerEnable |
- OHCI1394_LinkControl_CycleMaster |
- OHCI1394_LinkControl_CycleSource);
- }
- break;
-
- case CANCEL_REQUESTS:
- DBGMSG("Cancel request received");
- dma_trm_reset(&ohci->at_req_context);
- dma_trm_reset(&ohci->at_resp_context);
- break;
-
- default:
- PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet",
- cmd);
- break;
- }
- return retval;
-}
-
-/***********************************
- * rawiso ISO reception *
- ***********************************/
-
-/*
- We use either buffer-fill or packet-per-buffer DMA mode. The DMA
- buffer is split into "blocks" (regions described by one DMA
- descriptor). Each block must be one page or less in size, and
- must not cross a page boundary.
-
- There is one little wrinkle with buffer-fill mode: a packet that
- starts in the final block may wrap around into the first block. But
- the user API expects all packets to be contiguous. Our solution is
- to keep the very last page of the DMA buffer in reserve - if a
- packet spans the gap, we copy its tail into this page.
-*/
-
-struct ohci_iso_recv {
- struct ti_ohci *ohci;
-
- struct ohci1394_iso_tasklet task;
- int task_active;
-
- enum { BUFFER_FILL_MODE = 0,
- PACKET_PER_BUFFER_MODE = 1 } dma_mode;
-
- /* memory and PCI mapping for the DMA descriptors */
- struct dma_prog_region prog;
- struct dma_cmd *block; /* = (struct dma_cmd*) prog.virt */
-
- /* how many DMA blocks fit in the buffer */
- unsigned int nblocks;
-
- /* stride of DMA blocks */
- unsigned int buf_stride;
-
- /* number of blocks to batch between interrupts */
- int block_irq_interval;
-
- /* block that DMA will finish next */
- int block_dma;
-
- /* (buffer-fill only) block that the reader will release next */
- int block_reader;
-
- /* (buffer-fill only) bytes of buffer the reader has released,
- less than one block */
- int released_bytes;
-
- /* (buffer-fill only) buffer offset at which the next packet will appear */
- int dma_offset;
-
- /* OHCI DMA context control registers */
- u32 ContextControlSet;
- u32 ContextControlClear;
- u32 CommandPtr;
- u32 ContextMatch;
-};
-
-static void ohci_iso_recv_task(unsigned long data);
-static void ohci_iso_recv_stop(struct hpsb_iso *iso);
-static void ohci_iso_recv_shutdown(struct hpsb_iso *iso);
-static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync);
-static void ohci_iso_recv_program(struct hpsb_iso *iso);
-
-static int ohci_iso_recv_init(struct hpsb_iso *iso)
-{
- struct ti_ohci *ohci = iso->host->hostdata;
- struct ohci_iso_recv *recv;
- int ctx;
- int ret = -ENOMEM;
-
- recv = kmalloc(sizeof(*recv), GFP_KERNEL);
- if (!recv)
- return -ENOMEM;
-
- iso->hostdata = recv;
- recv->ohci = ohci;
- recv->task_active = 0;
- dma_prog_region_init(&recv->prog);
- recv->block = NULL;
-
- /* use buffer-fill mode, unless irq_interval is 1
- (note: multichannel requires buffer-fill) */
-
- if (((iso->irq_interval == 1 && iso->dma_mode == HPSB_ISO_DMA_OLD_ABI) ||
- iso->dma_mode == HPSB_ISO_DMA_PACKET_PER_BUFFER) && iso->channel != -1) {
- recv->dma_mode = PACKET_PER_BUFFER_MODE;
- } else {
- recv->dma_mode = BUFFER_FILL_MODE;
- }
-
- /* set nblocks, buf_stride, block_irq_interval */
-
- if (recv->dma_mode == BUFFER_FILL_MODE) {
- recv->buf_stride = PAGE_SIZE;
-
- /* one block per page of data in the DMA buffer, minus the final guard page */
- recv->nblocks = iso->buf_size/PAGE_SIZE - 1;
- if (recv->nblocks < 3) {
- DBGMSG("ohci_iso_recv_init: DMA buffer too small");
- goto err;
- }
-
- /* iso->irq_interval is in packets - translate that to blocks */
- if (iso->irq_interval == 1)
- recv->block_irq_interval = 1;
- else
- recv->block_irq_interval = iso->irq_interval *
- ((recv->nblocks+1)/iso->buf_packets);
- if (recv->block_irq_interval*4 > recv->nblocks)
- recv->block_irq_interval = recv->nblocks/4;
- if (recv->block_irq_interval < 1)
- recv->block_irq_interval = 1;
-
- } else {
- int max_packet_size;
-
- recv->nblocks = iso->buf_packets;
- recv->block_irq_interval = iso->irq_interval;
- if (recv->block_irq_interval * 4 > iso->buf_packets)
- recv->block_irq_interval = iso->buf_packets / 4;
- if (recv->block_irq_interval < 1)
- recv->block_irq_interval = 1;
-
- /* choose a buffer stride */
- /* must be a power of 2, and <= PAGE_SIZE */
-
- max_packet_size = iso->buf_size / iso->buf_packets;
-
- for (recv->buf_stride = 8; recv->buf_stride < max_packet_size;
- recv->buf_stride *= 2);
-
- if (recv->buf_stride*iso->buf_packets > iso->buf_size ||
- recv->buf_stride > PAGE_SIZE) {
- /* this shouldn't happen, but anyway... */
- DBGMSG("ohci_iso_recv_init: problem choosing a buffer stride");
- goto err;
- }
- }
-
- recv->block_reader = 0;
- recv->released_bytes = 0;
- recv->block_dma = 0;
- recv->dma_offset = 0;
-
- /* size of DMA program = one descriptor per block */
- if (dma_prog_region_alloc(&recv->prog,
- sizeof(struct dma_cmd) * recv->nblocks,
- recv->ohci->dev))
- goto err;
-
- recv->block = (struct dma_cmd*) recv->prog.kvirt;
-
- ohci1394_init_iso_tasklet(&recv->task,
- iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE :
- OHCI_ISO_RECEIVE,
- ohci_iso_recv_task, (unsigned long) iso);
-
- if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) {
- ret = -EBUSY;
- goto err;
- }
-
- recv->task_active = 1;
-
- /* recv context registers are spaced 32 bytes apart */
- ctx = recv->task.context;
- recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx;
- recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx;
- recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx;
- recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx;
-
- if (iso->channel == -1) {
- /* clear multi-channel selection mask */
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, 0xFFFFFFFF);
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, 0xFFFFFFFF);
- }
-
- /* write the DMA program */
- ohci_iso_recv_program(iso);
-
- DBGMSG("ohci_iso_recv_init: %s mode, DMA buffer is %lu pages"
- " (%u bytes), using %u blocks, buf_stride %u, block_irq_interval %d",
- recv->dma_mode == BUFFER_FILL_MODE ?
- "buffer-fill" : "packet-per-buffer",
- iso->buf_size/PAGE_SIZE, iso->buf_size,
- recv->nblocks, recv->buf_stride, recv->block_irq_interval);
-
- return 0;
-
-err:
- ohci_iso_recv_shutdown(iso);
- return ret;
-}
-
-static void ohci_iso_recv_stop(struct hpsb_iso *iso)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
-
- /* disable interrupts */
- reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context);
-
- /* halt DMA */
- ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL);
-}
-
-static void ohci_iso_recv_shutdown(struct hpsb_iso *iso)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
-
- if (recv->task_active) {
- ohci_iso_recv_stop(iso);
- ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task);
- recv->task_active = 0;
- }
-
- dma_prog_region_free(&recv->prog);
- kfree(recv);
- iso->hostdata = NULL;
-}
-
-/* set up a "gapped" ring buffer DMA program */
-static void ohci_iso_recv_program(struct hpsb_iso *iso)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
- int blk;
-
- /* address of 'branch' field in previous DMA descriptor */
- u32 *prev_branch = NULL;
-
- for (blk = 0; blk < recv->nblocks; blk++) {
- u32 control;
-
- /* the DMA descriptor */
- struct dma_cmd *cmd = &recv->block[blk];
-
- /* offset of the DMA descriptor relative to the DMA prog buffer */
- unsigned long prog_offset = blk * sizeof(struct dma_cmd);
-
- /* offset of this packet's data within the DMA buffer */
- unsigned long buf_offset = blk * recv->buf_stride;
-
- if (recv->dma_mode == BUFFER_FILL_MODE) {
- control = 2 << 28; /* INPUT_MORE */
- } else {
- control = 3 << 28; /* INPUT_LAST */
- }
-
- control |= 8 << 24; /* s = 1, update xferStatus and resCount */
-
- /* interrupt on last block, and at intervals */
- if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) {
- control |= 3 << 20; /* want interrupt */
- }
-
- control |= 3 << 18; /* enable branch to address */
- control |= recv->buf_stride;
-
- cmd->control = cpu_to_le32(control);
- cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset));
- cmd->branchAddress = 0; /* filled in on next loop */
- cmd->status = cpu_to_le32(recv->buf_stride);
-
- /* link the previous descriptor to this one */
- if (prev_branch) {
- *prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1);
- }
-
- prev_branch = &cmd->branchAddress;
- }
-
- /* the final descriptor's branch address and Z should be left at 0 */
-}
-
-/* listen or unlisten to a specific channel (multi-channel mode only) */
-static void ohci_iso_recv_change_channel(struct hpsb_iso *iso, unsigned char channel, int listen)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
- int reg, i;
-
- if (channel < 32) {
- reg = listen ? OHCI1394_IRMultiChanMaskLoSet : OHCI1394_IRMultiChanMaskLoClear;
- i = channel;
- } else {
- reg = listen ? OHCI1394_IRMultiChanMaskHiSet : OHCI1394_IRMultiChanMaskHiClear;
- i = channel - 32;
- }
-
- reg_write(recv->ohci, reg, (1 << i));
-
- /* issue a dummy read to force all PCI writes to be posted immediately */
- mb();
- reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static void ohci_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
- int i;
-
- for (i = 0; i < 64; i++) {
- if (mask & (1ULL << i)) {
- if (i < 32)
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoSet, (1 << i));
- else
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiSet, (1 << (i-32)));
- } else {
- if (i < 32)
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, (1 << i));
- else
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, (1 << (i-32)));
- }
- }
-
- /* issue a dummy read to force all PCI writes to be posted immediately */
- mb();
- reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
- struct ti_ohci *ohci = recv->ohci;
- u32 command, contextMatch;
-
- reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF);
- wmb();
-
- /* always keep ISO headers */
- command = (1 << 30);
-
- if (recv->dma_mode == BUFFER_FILL_MODE)
- command |= (1 << 31);
-
- reg_write(recv->ohci, recv->ContextControlSet, command);
-
- /* match on specified tags */
- contextMatch = tag_mask << 28;
-
- if (iso->channel == -1) {
- /* enable multichannel reception */
- reg_write(recv->ohci, recv->ContextControlSet, (1 << 28));
- } else {
- /* listen on channel */
- contextMatch |= iso->channel;
- }
-
- if (cycle != -1) {
- u32 seconds;
-
- /* enable cycleMatch */
- reg_write(recv->ohci, recv->ContextControlSet, (1 << 29));
-
- /* set starting cycle */
- cycle &= 0x1FFF;
-
- /* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
- just snarf them from the current time */
- seconds = reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
-
- /* advance one second to give some extra time for DMA to start */
- seconds += 1;
-
- cycle |= (seconds & 3) << 13;
-
- contextMatch |= cycle << 12;
- }
-
- if (sync != -1) {
- /* set sync flag on first DMA descriptor */
- struct dma_cmd *cmd = &recv->block[recv->block_dma];
- cmd->control |= cpu_to_le32(DMA_CTL_WAIT);
-
- /* match sync field */
- contextMatch |= (sync&0xf)<<8;
- }
-
- reg_write(recv->ohci, recv->ContextMatch, contextMatch);
-
- /* address of first descriptor block */
- command = dma_prog_region_offset_to_bus(&recv->prog,
- recv->block_dma * sizeof(struct dma_cmd));
- command |= 1; /* Z=1 */
-
- reg_write(recv->ohci, recv->CommandPtr, command);
-
- /* enable interrupts */
- reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << recv->task.context);
-
- wmb();
-
- /* run */
- reg_write(recv->ohci, recv->ContextControlSet, 0x8000);
-
- /* issue a dummy read of the cycle timer register to force
- all PCI writes to be posted immediately */
- mb();
- reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-
- /* check RUN */
- if (!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) {
- PRINT(KERN_ERR,
- "Error starting IR DMA (ContextControl 0x%08x)\n",
- reg_read(recv->ohci, recv->ContextControlSet));
- return -1;
- }
-
- return 0;
-}
-
-static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block)
-{
- /* re-use the DMA descriptor for the block */
- /* by linking the previous descriptor to it */
-
- int next_i = block;
- int prev_i = (next_i == 0) ? (recv->nblocks - 1) : (next_i - 1);
-
- struct dma_cmd *next = &recv->block[next_i];
- struct dma_cmd *prev = &recv->block[prev_i];
-
- /* ignore out-of-range requests */
- if ((block < 0) || (block > recv->nblocks))
- return;
-
- /* 'next' becomes the new end of the DMA chain,
- so disable branch and enable interrupt */
- next->branchAddress = 0;
- next->control |= cpu_to_le32(3 << 20);
- next->status = cpu_to_le32(recv->buf_stride);
-
- /* link prev to next */
- prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog,
- sizeof(struct dma_cmd) * next_i)
- | 1); /* Z=1 */
-
- /* disable interrupt on previous DMA descriptor, except at intervals */
- if ((prev_i % recv->block_irq_interval) == 0) {
- prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */
- } else {
- prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */
- }
- wmb();
-
- /* wake up DMA in case it fell asleep */
- reg_write(recv->ohci, recv->ContextControlSet, (1 << 12));
-}
-
-static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv,
- struct hpsb_iso_packet_info *info)
-{
- /* release the memory where the packet was */
- recv->released_bytes += info->total_len;
-
- /* have we released enough memory for one block? */
- while (recv->released_bytes > recv->buf_stride) {
- ohci_iso_recv_release_block(recv, recv->block_reader);
- recv->block_reader = (recv->block_reader + 1) % recv->nblocks;
- recv->released_bytes -= recv->buf_stride;
- }
-}
-
-static inline void ohci_iso_recv_release(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
- if (recv->dma_mode == BUFFER_FILL_MODE) {
- ohci_iso_recv_bufferfill_release(recv, info);
- } else {
- ohci_iso_recv_release_block(recv, info - iso->infos);
- }
-}
-
-/* parse all packets from blocks that have been fully received */
-static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
- int wake = 0;
- int runaway = 0;
- struct ti_ohci *ohci = recv->ohci;
-
- while (1) {
- /* we expect the next parsable packet to begin at recv->dma_offset */
- /* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */
-
- unsigned int offset;
- unsigned short len, cycle, total_len;
- unsigned char channel, tag, sy;
-
- unsigned char *p = iso->data_buf.kvirt;
-
- unsigned int this_block = recv->dma_offset/recv->buf_stride;
-
- /* don't loop indefinitely */
- if (runaway++ > 100000) {
- atomic_inc(&iso->overflows);
- PRINT(KERN_ERR,
- "IR DMA error - Runaway during buffer parsing!\n");
- break;
- }
-
- /* stop parsing once we arrive at block_dma (i.e. don't get ahead of DMA) */
- if (this_block == recv->block_dma)
- break;
-
- wake = 1;
-
- /* parse data length, tag, channel, and sy */
-
- /* note: we keep our own local copies of 'len' and 'offset'
- so the user can't mess with them by poking in the mmap area */
-
- len = p[recv->dma_offset+2] | (p[recv->dma_offset+3] << 8);
-
- if (len > 4096) {
- PRINT(KERN_ERR,
- "IR DMA error - bogus 'len' value %u\n", len);
- }
-
- channel = p[recv->dma_offset+1] & 0x3F;
- tag = p[recv->dma_offset+1] >> 6;
- sy = p[recv->dma_offset+0] & 0xF;
-
- /* advance to data payload */
- recv->dma_offset += 4;
-
- /* check for wrap-around */
- if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
- recv->dma_offset -= recv->buf_stride*recv->nblocks;
- }
-
- /* dma_offset now points to the first byte of the data payload */
- offset = recv->dma_offset;
-
- /* advance to xferStatus/timeStamp */
- recv->dma_offset += len;
-
- total_len = len + 8; /* 8 bytes header+trailer in OHCI packet */
- /* payload is padded to 4 bytes */
- if (len % 4) {
- recv->dma_offset += 4 - (len%4);
- total_len += 4 - (len%4);
- }
-
- /* check for wrap-around */
- if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
- /* uh oh, the packet data wraps from the last
- to the first DMA block - make the packet
- contiguous by copying its "tail" into the
- guard page */
-
- int guard_off = recv->buf_stride*recv->nblocks;
- int tail_len = len - (guard_off - offset);
-
- if (tail_len > 0 && tail_len < recv->buf_stride) {
- memcpy(iso->data_buf.kvirt + guard_off,
- iso->data_buf.kvirt,
- tail_len);
- }
-
- recv->dma_offset -= recv->buf_stride*recv->nblocks;
- }
-
- /* parse timestamp */
- cycle = p[recv->dma_offset+0] | (p[recv->dma_offset+1]<<8);
- cycle &= 0x1FFF;
-
- /* advance to next packet */
- recv->dma_offset += 4;
-
- /* check for wrap-around */
- if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
- recv->dma_offset -= recv->buf_stride*recv->nblocks;
- }
-
- hpsb_iso_packet_received(iso, offset, len, total_len, cycle, channel, tag, sy);
- }
-
- if (wake)
- hpsb_iso_wake(iso);
-}
-
-static void ohci_iso_recv_bufferfill_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
- int loop;
- struct ti_ohci *ohci = recv->ohci;
-
- /* loop over all blocks */
- for (loop = 0; loop < recv->nblocks; loop++) {
-
- /* check block_dma to see if it's done */
- struct dma_cmd *im = &recv->block[recv->block_dma];
-
- /* check the DMA descriptor for new writes to xferStatus */
- u16 xferstatus = le32_to_cpu(im->status) >> 16;
-
- /* rescount is the number of bytes *remaining to be written* in the block */
- u16 rescount = le32_to_cpu(im->status) & 0xFFFF;
-
- unsigned char event = xferstatus & 0x1F;
-
- if (!event) {
- /* nothing has happened to this block yet */
- break;
- }
-
- if (event != 0x11) {
- atomic_inc(&iso->overflows);
- PRINT(KERN_ERR,
- "IR DMA error - OHCI error code 0x%02x\n", event);
- }
-
- if (rescount != 0) {
- /* the card is still writing to this block;
- we can't touch it until it's done */
- break;
- }
-
- /* OK, the block is finished... */
-
- /* sync our view of the block */
- dma_region_sync_for_cpu(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride);
-
- /* reset the DMA descriptor */
- im->status = recv->buf_stride;
-
- /* advance block_dma */
- recv->block_dma = (recv->block_dma + 1) % recv->nblocks;
-
- if ((recv->block_dma+1) % recv->nblocks == recv->block_reader) {
- atomic_inc(&iso->overflows);
- DBGMSG("ISO reception overflow - "
- "ran out of DMA blocks");
- }
- }
-
- /* parse any packets that have arrived */
- ohci_iso_recv_bufferfill_parse(iso, recv);
-}
-
-static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
- int count;
- int wake = 0;
- struct ti_ohci *ohci = recv->ohci;
-
- /* loop over the entire buffer */
- for (count = 0; count < recv->nblocks; count++) {
- u32 packet_len = 0;
-
- /* pointer to the DMA descriptor */
- struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma;
-
- /* check the DMA descriptor for new writes to xferStatus */
- u16 xferstatus = le32_to_cpu(il->status) >> 16;
- u16 rescount = le32_to_cpu(il->status) & 0xFFFF;
-
- unsigned char event = xferstatus & 0x1F;
-
- if (!event) {
- /* this packet hasn't come in yet; we are done for now */
- goto out;
- }
-
- if (event == 0x11) {
- /* packet received successfully! */
-
- /* rescount is the number of bytes *remaining* in the packet buffer,
- after the packet was written */
- packet_len = recv->buf_stride - rescount;
-
- } else if (event == 0x02) {
- PRINT(KERN_ERR, "IR DMA error - packet too long for buffer\n");
- } else if (event) {
- PRINT(KERN_ERR, "IR DMA error - OHCI error code 0x%02x\n", event);
- }
-
- /* sync our view of the buffer */
- dma_region_sync_for_cpu(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride);
-
- /* record the per-packet info */
- {
- /* iso header is 8 bytes ahead of the data payload */
- unsigned char *hdr;
-
- unsigned int offset;
- unsigned short cycle;
- unsigned char channel, tag, sy;
-
- offset = iso->pkt_dma * recv->buf_stride;
- hdr = iso->data_buf.kvirt + offset;
-
- /* skip iso header */
- offset += 8;
- packet_len -= 8;
-
- cycle = (hdr[0] | (hdr[1] << 8)) & 0x1FFF;
- channel = hdr[5] & 0x3F;
- tag = hdr[5] >> 6;
- sy = hdr[4] & 0xF;
-
- hpsb_iso_packet_received(iso, offset, packet_len,
- recv->buf_stride, cycle, channel, tag, sy);
- }
-
- /* reset the DMA descriptor */
- il->status = recv->buf_stride;
-
- wake = 1;
- recv->block_dma = iso->pkt_dma;
- }
-
-out:
- if (wake)
- hpsb_iso_wake(iso);
-}
-
-static void ohci_iso_recv_task(unsigned long data)
-{
- struct hpsb_iso *iso = (struct hpsb_iso*) data;
- struct ohci_iso_recv *recv = iso->hostdata;
-
- if (recv->dma_mode == BUFFER_FILL_MODE)
- ohci_iso_recv_bufferfill_task(iso, recv);
- else
- ohci_iso_recv_packetperbuf_task(iso, recv);
-}
-
-/***********************************
- * rawiso ISO transmission *
- ***********************************/
-
-struct ohci_iso_xmit {
- struct ti_ohci *ohci;
- struct dma_prog_region prog;
- struct ohci1394_iso_tasklet task;
- int task_active;
- int last_cycle;
- atomic_t skips;
-
- u32 ContextControlSet;
- u32 ContextControlClear;
- u32 CommandPtr;
-};
-
-/* transmission DMA program:
- one OUTPUT_MORE_IMMEDIATE for the IT header
- one OUTPUT_LAST for the buffer data */
-
-struct iso_xmit_cmd {
- struct dma_cmd output_more_immediate;
- u8 iso_hdr[8];
- u32 unused[2];
- struct dma_cmd output_last;
-};
-
-static int ohci_iso_xmit_init(struct hpsb_iso *iso);
-static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle);
-static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso);
-static void ohci_iso_xmit_task(unsigned long data);
-
-static int ohci_iso_xmit_init(struct hpsb_iso *iso)
-{
- struct ohci_iso_xmit *xmit;
- unsigned int prog_size;
- int ctx;
- int ret = -ENOMEM;
-
- xmit = kmalloc(sizeof(*xmit), GFP_KERNEL);
- if (!xmit)
- return -ENOMEM;
-
- iso->hostdata = xmit;
- xmit->ohci = iso->host->hostdata;
- xmit->task_active = 0;
- xmit->last_cycle = -1;
- atomic_set(&iso->skips, 0);
-
- dma_prog_region_init(&xmit->prog);
-
- prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets;
-
- if (dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev))
- goto err;
-
- ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT,
- ohci_iso_xmit_task, (unsigned long) iso);
-
- if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) {
- ret = -EBUSY;
- goto err;
- }
-
- xmit->task_active = 1;
-
- /* xmit context registers are spaced 16 bytes apart */
- ctx = xmit->task.context;
- xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx;
- xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx;
- xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx;
-
- return 0;
-
-err:
- ohci_iso_xmit_shutdown(iso);
- return ret;
-}
-
-static void ohci_iso_xmit_stop(struct hpsb_iso *iso)
-{
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
-
- /* disable interrupts */
- reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context);
-
- /* halt DMA */
- if (ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL)) {
- /* XXX the DMA context will lock up if you try to send too much data! */
- PRINT(KERN_ERR,
- "you probably exceeded the OHCI card's bandwidth limit - "
- "reload the module and reduce xmit bandwidth");
- }
-}
-
-static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso)
-{
- struct ohci_iso_xmit *xmit = iso->hostdata;
-
- if (xmit->task_active) {
- ohci_iso_xmit_stop(iso);
- ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task);
- xmit->task_active = 0;
- }
-
- dma_prog_region_free(&xmit->prog);
- kfree(xmit);
- iso->hostdata = NULL;
-}
-
-static void ohci_iso_xmit_task(unsigned long data)
-{
- struct hpsb_iso *iso = (struct hpsb_iso*) data;
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
- int wake = 0;
- int count;
-
- /* check the whole buffer if necessary, starting at pkt_dma */
- for (count = 0; count < iso->buf_packets; count++) {
- int cycle;
-
- /* DMA descriptor */
- struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma);
-
- /* check for new writes to xferStatus */
- u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16;
- u8 event = xferstatus & 0x1F;
-
- if (!event) {
- /* packet hasn't been sent yet; we are done for now */
- break;
- }
-
- if (event != 0x11)
- PRINT(KERN_ERR,
- "IT DMA error - OHCI error code 0x%02x\n", event);
-
- /* at least one packet went out, so wake up the writer */
- wake = 1;
-
- /* parse cycle */
- cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF;
-
- if (xmit->last_cycle > -1) {
- int cycle_diff = cycle - xmit->last_cycle;
- int skip;
-
- /* unwrap */
- if (cycle_diff < 0) {
- cycle_diff += 8000;
- if (cycle_diff < 0)
- PRINT(KERN_ERR, "bogus cycle diff %d\n",
- cycle_diff);
- }
-
- skip = cycle_diff - 1;
- if (skip > 0) {
- DBGMSG("skipped %d cycles without packet loss", skip);
- atomic_add(skip, &iso->skips);
- }
- }
- xmit->last_cycle = cycle;
-
- /* tell the subsystem the packet has gone out */
- hpsb_iso_packet_sent(iso, cycle, event != 0x11);
-
- /* reset the DMA descriptor for next time */
- cmd->output_last.status = 0;
- }
-
- if (wake)
- hpsb_iso_wake(iso);
-}
-
-static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
-{
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
-
- int next_i, prev_i;
- struct iso_xmit_cmd *next, *prev;
-
- unsigned int offset;
- unsigned short len;
- unsigned char tag, sy;
-
- /* check that the packet doesn't cross a page boundary
- (we could allow this if we added OUTPUT_MORE descriptor support) */
- if (cross_bound(info->offset, info->len)) {
- PRINT(KERN_ERR,
- "rawiso xmit: packet %u crosses a page boundary",
- iso->first_packet);
- return -EINVAL;
- }
-
- offset = info->offset;
- len = info->len;
- tag = info->tag;
- sy = info->sy;
-
- /* sync up the card's view of the buffer */
- dma_region_sync_for_device(&iso->data_buf, offset, len);
-
- /* append first_packet to the DMA chain */
- /* by linking the previous descriptor to it */
- /* (next will become the new end of the DMA chain) */
-
- next_i = iso->first_packet;
- prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1);
-
- next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i);
- prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i);
-
- /* set up the OUTPUT_MORE_IMMEDIATE descriptor */
- memset(next, 0, sizeof(struct iso_xmit_cmd));
- next->output_more_immediate.control = cpu_to_le32(0x02000008);
-
- /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */
-
- /* tcode = 0xA, and sy */
- next->iso_hdr[0] = 0xA0 | (sy & 0xF);
-
- /* tag and channel number */
- next->iso_hdr[1] = (tag << 6) | (iso->channel & 0x3F);
-
- /* transmission speed */
- next->iso_hdr[2] = iso->speed & 0x7;
-
- /* payload size */
- next->iso_hdr[6] = len & 0xFF;
- next->iso_hdr[7] = len >> 8;
-
- /* set up the OUTPUT_LAST */
- next->output_last.control = cpu_to_le32(1 << 28);
- next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */
- next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */
- next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */
- next->output_last.control |= cpu_to_le32(len);
-
- /* payload bus address */
- next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset));
-
- /* leave branchAddress at zero for now */
-
- /* re-write the previous DMA descriptor to chain to this one */
-
- /* set prev branch address to point to next (Z=3) */
- prev->output_last.branchAddress = cpu_to_le32(
- dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3);
-
- /*
- * Link the skip address to this descriptor itself. This causes a
- * context to skip a cycle whenever lost cycles or FIFO overruns occur,
- * without dropping the data at that point the application should then
- * decide whether this is an error condition or not. Some protocols
- * can deal with this by dropping some rate-matching padding packets.
- */
- next->output_more_immediate.branchAddress =
- prev->output_last.branchAddress;
-
- /* disable interrupt, unless required by the IRQ interval */
- if (prev_i % iso->irq_interval) {
- prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */
- } else {
- prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */
- }
-
- wmb();
-
- /* wake DMA in case it is sleeping */
- reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12);
-
- /* issue a dummy read of the cycle timer to force all PCI
- writes to be posted immediately */
- mb();
- reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer);
-
- return 0;
-}
-
-static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle)
-{
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
-
- /* clear out the control register */
- reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF);
- wmb();
-
- /* address and length of first descriptor block (Z=3) */
- reg_write(xmit->ohci, xmit->CommandPtr,
- dma_prog_region_offset_to_bus(&xmit->prog, iso->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3);
-
- /* cycle match */
- if (cycle != -1) {
- u32 start = cycle & 0x1FFF;
-
- /* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
- just snarf them from the current time */
- u32 seconds = reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
-
- /* advance one second to give some extra time for DMA to start */
- seconds += 1;
-
- start |= (seconds & 3) << 13;
-
- reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16));
- }
-
- /* enable interrupts */
- reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << xmit->task.context);
-
- /* run */
- reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000);
- mb();
-
- /* wait 100 usec to give the card time to go active */
- udelay(100);
-
- /* check the RUN bit */
- if (!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) {
- PRINT(KERN_ERR, "Error starting IT DMA (ContextControl 0x%08x)\n",
- reg_read(xmit->ohci, xmit->ContextControlSet));
- return -1;
- }
-
- return 0;
-}
-
-static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, unsigned long arg)
-{
-
- switch(cmd) {
- case XMIT_INIT:
- return ohci_iso_xmit_init(iso);
- case XMIT_START:
- return ohci_iso_xmit_start(iso, arg);
- case XMIT_STOP:
- ohci_iso_xmit_stop(iso);
- return 0;
- case XMIT_QUEUE:
- return ohci_iso_xmit_queue(iso, (struct hpsb_iso_packet_info*) arg);
- case XMIT_SHUTDOWN:
- ohci_iso_xmit_shutdown(iso);
- return 0;
-
- case RECV_INIT:
- return ohci_iso_recv_init(iso);
- case RECV_START: {
- int *args = (int*) arg;
- return ohci_iso_recv_start(iso, args[0], args[1], args[2]);
- }
- case RECV_STOP:
- ohci_iso_recv_stop(iso);
- return 0;
- case RECV_RELEASE:
- ohci_iso_recv_release(iso, (struct hpsb_iso_packet_info*) arg);
- return 0;
- case RECV_FLUSH:
- ohci_iso_recv_task((unsigned long) iso);
- return 0;
- case RECV_SHUTDOWN:
- ohci_iso_recv_shutdown(iso);
- return 0;
- case RECV_LISTEN_CHANNEL:
- ohci_iso_recv_change_channel(iso, arg, 1);
- return 0;
- case RECV_UNLISTEN_CHANNEL:
- ohci_iso_recv_change_channel(iso, arg, 0);
- return 0;
- case RECV_SET_CHANNEL_MASK:
- ohci_iso_recv_set_channel_mask(iso, *((u64*) arg));
- return 0;
-
- default:
- PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet",
- cmd);
- break;
- }
- return -EINVAL;
-}
-
-/***************************************
- * IEEE-1394 functionality section END *
- ***************************************/
-
-
-/********************************************************
- * Global stuff (interrupt handler, init/shutdown code) *
- ********************************************************/
-
-static void dma_trm_reset(struct dma_trm_ctx *d)
-{
- unsigned long flags;
- LIST_HEAD(packet_list);
- struct ti_ohci *ohci = d->ohci;
- struct hpsb_packet *packet, *ptmp;
-
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
- /* Lock the context, reset it and release it. Move the packets
- * that were pending in the context to packet_list and free
- * them after releasing the lock. */
-
- spin_lock_irqsave(&d->lock, flags);
-
- list_splice_init(&d->fifo_list, &packet_list);
- list_splice_init(&d->pending_list, &packet_list);
-
- d->branchAddrPtr = NULL;
- d->sent_ind = d->prg_ind;
- d->free_prgs = d->num_desc;
-
- spin_unlock_irqrestore(&d->lock, flags);
-
- if (list_empty(&packet_list))
- return;
-
- PRINT(KERN_INFO, "AT dma reset ctx=%d, aborting transmission", d->ctx);
-
- /* Now process subsystem callbacks for the packets from this
- * context. */
- list_for_each_entry_safe(packet, ptmp, &packet_list, driver_list) {
- list_del_init(&packet->driver_list);
- hpsb_packet_sent(ohci->host, packet, ACKX_ABORTED);
- }
-}
-
-static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci,
- quadlet_t rx_event,
- quadlet_t tx_event)
-{
- struct ohci1394_iso_tasklet *t;
- unsigned long mask;
- unsigned long flags;
-
- spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
- list_for_each_entry(t, &ohci->iso_tasklet_list, link) {
- mask = 1 << t->context;
-
- if (t->type == OHCI_ISO_TRANSMIT) {
- if (tx_event & mask)
- tasklet_schedule(&t->tasklet);
- } else {
- /* OHCI_ISO_RECEIVE or OHCI_ISO_MULTICHANNEL_RECEIVE */
- if (rx_event & mask)
- tasklet_schedule(&t->tasklet);
- }
- }
-
- spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-}
-
-static irqreturn_t ohci_irq_handler(int irq, void *dev_id)
-{
- quadlet_t event, node_id;
- struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
- struct hpsb_host *host = ohci->host;
- int phyid = -1, isroot = 0;
- unsigned long flags;
-
- /* Read and clear the interrupt event register. Don't clear
- * the busReset event, though. This is done when we get the
- * selfIDComplete interrupt. */
- spin_lock_irqsave(&ohci->event_lock, flags);
- event = reg_read(ohci, OHCI1394_IntEventClear);
- reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
- spin_unlock_irqrestore(&ohci->event_lock, flags);
-
- if (!event)
- return IRQ_NONE;
-
- /* If event is ~(u32)0 cardbus card was ejected. In this case
- * we just return, and clean up in the ohci1394_pci_remove
- * function. */
- if (event == ~(u32) 0) {
- DBGMSG("Device removed.");
- return IRQ_NONE;
- }
-
- DBGMSG("IntEvent: %08x", event);
-
- if (event & OHCI1394_unrecoverableError) {
- int ctx;
- PRINT(KERN_ERR, "Unrecoverable error!");
-
- if (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Req Tx Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsReqTrContextControlSet),
- reg_read(ohci, OHCI1394_AsReqTrCommandPtr));
-
- if (reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Rsp Tx Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsRspTrContextControlSet),
- reg_read(ohci, OHCI1394_AsRspTrCommandPtr));
-
- if (reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Req Rcv Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsReqRcvContextControlSet),
- reg_read(ohci, OHCI1394_AsReqRcvCommandPtr));
-
- if (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Rsp Rcv Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsRspRcvContextControlSet),
- reg_read(ohci, OHCI1394_AsRspRcvCommandPtr));
-
- for (ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) {
- if (reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800)
- PRINT(KERN_ERR, "Iso Xmit %d Context died: "
- "ctrl[%08x] cmdptr[%08x]", ctx,
- reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)),
- reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx)));
- }
-
- for (ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) {
- if (reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800)
- PRINT(KERN_ERR, "Iso Recv %d Context died: "
- "ctrl[%08x] cmdptr[%08x] match[%08x]", ctx,
- reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)),
- reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)),
- reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx)));
- }
-
- event &= ~OHCI1394_unrecoverableError;
- }
- if (event & OHCI1394_postedWriteErr) {
- PRINT(KERN_ERR, "physical posted write error");
- /* no recovery strategy yet, had to involve protocol drivers */
- event &= ~OHCI1394_postedWriteErr;
- }
- if (event & OHCI1394_cycleTooLong) {
- if(printk_ratelimit())
- PRINT(KERN_WARNING, "isochronous cycle too long");
- else
- DBGMSG("OHCI1394_cycleTooLong");
- reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_CycleMaster);
- event &= ~OHCI1394_cycleTooLong;
- }
- if (event & OHCI1394_cycleInconsistent) {
- /* We subscribe to the cycleInconsistent event only to
- * clear the corresponding event bit... otherwise,
- * isochronous cycleMatch DMA won't work. */
- DBGMSG("OHCI1394_cycleInconsistent");
- event &= ~OHCI1394_cycleInconsistent;
- }
- if (event & OHCI1394_busReset) {
- /* The busReset event bit can't be cleared during the
- * selfID phase, so we disable busReset interrupts, to
- * avoid burying the cpu in interrupt requests. */
- spin_lock_irqsave(&ohci->event_lock, flags);
- reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
-
- if (ohci->check_busreset) {
- int loop_count = 0;
-
- udelay(10);
-
- while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
- reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-
- spin_unlock_irqrestore(&ohci->event_lock, flags);
- udelay(10);
- spin_lock_irqsave(&ohci->event_lock, flags);
-
- /* The loop counter check is to prevent the driver
- * from remaining in this state forever. For the
- * initial bus reset, the loop continues for ever
- * and the system hangs, until some device is plugged-in
- * or out manually into a port! The forced reset seems
- * to solve this problem. This mainly effects nForce2. */
- if (loop_count > 10000) {
- ohci_devctl(host, RESET_BUS, LONG_RESET);
- DBGMSG("Detected bus-reset loop. Forced a bus reset!");
- loop_count = 0;
- }
-
- loop_count++;
- }
- }
- spin_unlock_irqrestore(&ohci->event_lock, flags);
- if (!host->in_bus_reset) {
- DBGMSG("irq_handler: Bus reset requested");
-
- /* Subsystem call */
- hpsb_bus_reset(ohci->host);
- }
- event &= ~OHCI1394_busReset;
- }
- if (event & OHCI1394_reqTxComplete) {
- struct dma_trm_ctx *d = &ohci->at_req_context;
- DBGMSG("Got reqTxComplete interrupt "
- "status=0x%08X", reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear,
- "reqTxComplete");
- else
- dma_trm_tasklet((unsigned long)d);
- //tasklet_schedule(&d->task);
- event &= ~OHCI1394_reqTxComplete;
- }
- if (event & OHCI1394_respTxComplete) {
- struct dma_trm_ctx *d = &ohci->at_resp_context;
- DBGMSG("Got respTxComplete interrupt "
- "status=0x%08X", reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear,
- "respTxComplete");
- else
- tasklet_schedule(&d->task);
- event &= ~OHCI1394_respTxComplete;
- }
- if (event & OHCI1394_RQPkt) {
- struct dma_rcv_ctx *d = &ohci->ar_req_context;
- DBGMSG("Got RQPkt interrupt status=0x%08X",
- reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt");
- else
- tasklet_schedule(&d->task);
- event &= ~OHCI1394_RQPkt;
- }
- if (event & OHCI1394_RSPkt) {
- struct dma_rcv_ctx *d = &ohci->ar_resp_context;
- DBGMSG("Got RSPkt interrupt status=0x%08X",
- reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt");
- else
- tasklet_schedule(&d->task);
- event &= ~OHCI1394_RSPkt;
- }
- if (event & OHCI1394_isochRx) {
- quadlet_t rx_event;
-
- rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event);
- ohci_schedule_iso_tasklets(ohci, rx_event, 0);
- event &= ~OHCI1394_isochRx;
- }
- if (event & OHCI1394_isochTx) {
- quadlet_t tx_event;
-
- tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event);
- ohci_schedule_iso_tasklets(ohci, 0, tx_event);
- event &= ~OHCI1394_isochTx;
- }
- if (event & OHCI1394_selfIDComplete) {
- if (host->in_bus_reset) {
- node_id = reg_read(ohci, OHCI1394_NodeID);
-
- if (!(node_id & 0x80000000)) {
- PRINT(KERN_ERR,
- "SelfID received, but NodeID invalid "
- "(probably new bus reset occurred): %08X",
- node_id);
- goto selfid_not_valid;
- }
-
- phyid = node_id & 0x0000003f;
- isroot = (node_id & 0x40000000) != 0;
-
- DBGMSG("SelfID interrupt received "
- "(phyid %d, %s)", phyid,
- (isroot ? "root" : "not root"));
-
- handle_selfid(ohci, host, phyid, isroot);
-
- /* Clear the bus reset event and re-enable the
- * busReset interrupt. */
- spin_lock_irqsave(&ohci->event_lock, flags);
- reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
- reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
- spin_unlock_irqrestore(&ohci->event_lock, flags);
-
- /* Turn on phys dma reception.
- *
- * TODO: Enable some sort of filtering management.
- */
- if (phys_dma) {
- reg_write(ohci, OHCI1394_PhyReqFilterHiSet,
- 0xffffffff);
- reg_write(ohci, OHCI1394_PhyReqFilterLoSet,
- 0xffffffff);
- }
-
- DBGMSG("PhyReqFilter=%08x%08x",
- reg_read(ohci, OHCI1394_PhyReqFilterHiSet),
- reg_read(ohci, OHCI1394_PhyReqFilterLoSet));
-
- hpsb_selfid_complete(host, phyid, isroot);
- } else
- PRINT(KERN_ERR,
- "SelfID received outside of bus reset sequence");
-
-selfid_not_valid:
- event &= ~OHCI1394_selfIDComplete;
- }
-
- /* Make sure we handle everything, just in case we accidentally
- * enabled an interrupt that we didn't write a handler for. */
- if (event)
- PRINT(KERN_ERR, "Unhandled interrupt(s) 0x%08x",
- event);
-
- return IRQ_HANDLED;
-}
-
-/* Put the buffer back into the dma context */
-static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx)
-{
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- DBGMSG("Inserting dma buf ctx=%d idx=%d", d->ctx, idx);
-
- d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size);
- d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0);
- idx = (idx + d->num_desc - 1 ) % d->num_desc;
- d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001);
-
- /* To avoid a race, ensure 1394 interface hardware sees the inserted
- * context program descriptors before it sees the wakeup bit set. */
- wmb();
-
- /* wake up the dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
- PRINT(KERN_INFO,
- "Waking dma ctx=%d ... processing is probably too slow",
- d->ctx);
- }
-
- /* do this always, to avoid race condition */
- reg_write(ohci, d->ctrlSet, 0x1000);
-}
-
-#define cond_le32_to_cpu(data, noswap) \
- (noswap ? data : le32_to_cpu(data))
-
-static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0,
- -1, 0, -1, 0, -1, -1, 16, -1};
-
-/*
- * Determine the length of a packet in the buffer
- * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca>
- */
-static inline int packet_length(struct dma_rcv_ctx *d, int idx,
- quadlet_t *buf_ptr, int offset,
- unsigned char tcode, int noswap)
-{
- int length = -1;
-
- if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) {
- length = TCODE_SIZE[tcode];
- if (length == 0) {
- if (offset + 12 >= d->buf_size) {
- length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc]
- [3 - ((d->buf_size - offset) >> 2)], noswap) >> 16);
- } else {
- length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16);
- }
- length += 20;
- }
- } else if (d->type == DMA_CTX_ISO) {
- /* Assumption: buffer fill mode with header/trailer */
- length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8;
- }
-
- if (length > 0 && length % 4)
- length += 4 - (length % 4);
-
- return length;
-}
-
-/* Tasklet that processes dma receive buffers */
-static void dma_rcv_tasklet (unsigned long data)
-{
- struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data;
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- unsigned int split_left, idx, offset, rescount;
- unsigned char tcode;
- int length, bytes_left, ack;
- unsigned long flags;
- quadlet_t *buf_ptr;
- char *split_ptr;
- char msg[256];
-
- spin_lock_irqsave(&d->lock, flags);
-
- idx = d->buf_ind;
- offset = d->buf_offset;
- buf_ptr = d->buf_cpu[idx] + offset/4;
-
- rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
- bytes_left = d->buf_size - rescount - offset;
-
- while (bytes_left > 0) {
- tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf;
-
- /* packet_length() will return < 4 for an error */
- length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming);
-
- if (length < 4) { /* something is wrong */
- sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d",
- tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming),
- d->ctx, length);
- ohci1394_stop_context(ohci, d->ctrlClear, msg);
- spin_unlock_irqrestore(&d->lock, flags);
- return;
- }
-
- /* The first case is where we have a packet that crosses
- * over more than one descriptor. The next case is where
- * it's all in the first descriptor. */
- if ((offset + length) > d->buf_size) {
- DBGMSG("Split packet rcv'd");
- if (length > d->split_buf_size) {
- ohci1394_stop_context(ohci, d->ctrlClear,
- "Split packet size exceeded");
- d->buf_ind = idx;
- d->buf_offset = offset;
- spin_unlock_irqrestore(&d->lock, flags);
- return;
- }
-
- if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status)
- == d->buf_size) {
- /* Other part of packet not written yet.
- * this should never happen I think
- * anyway we'll get it on the next call. */
- PRINT(KERN_INFO,
- "Got only half a packet!");
- d->buf_ind = idx;
- d->buf_offset = offset;
- spin_unlock_irqrestore(&d->lock, flags);
- return;
- }
-
- split_left = length;
- split_ptr = (char *)d->spb;
- memcpy(split_ptr,buf_ptr,d->buf_size-offset);
- split_left -= d->buf_size-offset;
- split_ptr += d->buf_size-offset;
- insert_dma_buffer(d, idx);
- idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf_cpu[idx];
- offset=0;
-
- while (split_left >= d->buf_size) {
- memcpy(split_ptr,buf_ptr,d->buf_size);
- split_ptr += d->buf_size;
- split_left -= d->buf_size;
- insert_dma_buffer(d, idx);
- idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf_cpu[idx];
- }
-
- if (split_left > 0) {
- memcpy(split_ptr, buf_ptr, split_left);
- offset = split_left;
- buf_ptr += offset/4;
- }
- } else {
- DBGMSG("Single packet rcv'd");
- memcpy(d->spb, buf_ptr, length);
- offset += length;
- buf_ptr += length/4;
- if (offset==d->buf_size) {
- insert_dma_buffer(d, idx);
- idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf_cpu[idx];
- offset=0;
- }
- }
-
- /* We get one phy packet to the async descriptor for each
- * bus reset. We always ignore it. */
- if (tcode != OHCI1394_TCODE_PHY) {
- if (!ohci->no_swap_incoming)
- header_le32_to_cpu(d->spb, tcode);
- DBGMSG("Packet received from node"
- " %d ack=0x%02X spd=%d tcode=0x%X"
- " length=%d ctx=%d tlabel=%d",
- (d->spb[1]>>16)&0x3f,
- (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f,
- (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3,
- tcode, length, d->ctx,
- (d->spb[0]>>10)&0x3f);
-
- ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f)
- == 0x11) ? 1 : 0;
-
- hpsb_packet_received(ohci->host, d->spb,
- length-4, ack);
- }
-#ifdef OHCI1394_DEBUG
- else
- PRINT (KERN_DEBUG, "Got phy packet ctx=%d ... discarded",
- d->ctx);
-#endif
-
- rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
-
- bytes_left = d->buf_size - rescount - offset;
-
- }
-
- d->buf_ind = idx;
- d->buf_offset = offset;
-
- spin_unlock_irqrestore(&d->lock, flags);
-}
-
-/* Bottom half that processes sent packets */
-static void dma_trm_tasklet (unsigned long data)
-{
- struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- struct hpsb_packet *packet, *ptmp;
- unsigned long flags;
- u32 status, ack;
- size_t datasize;
-
- spin_lock_irqsave(&d->lock, flags);
-
- list_for_each_entry_safe(packet, ptmp, &d->fifo_list, driver_list) {
- datasize = packet->data_size;
- if (datasize && packet->type != hpsb_raw)
- status = le32_to_cpu(
- d->prg_cpu[d->sent_ind]->end.status) >> 16;
- else
- status = le32_to_cpu(
- d->prg_cpu[d->sent_ind]->begin.status) >> 16;
-
- if (status == 0)
- /* this packet hasn't been sent yet*/
- break;
-
-#ifdef OHCI1394_DEBUG
- if (datasize)
- if (((le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf) == 0xa)
- DBGMSG("Stream packet sent to channel %d tcode=0x%X "
- "ack=0x%X spd=%d dataLength=%d ctx=%d",
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>8)&0x3f,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
- status&0x1f, (status>>5)&0x3,
- le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16,
- d->ctx);
- else
- DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
- "%d ack=0x%X spd=%d dataLength=%d ctx=%d",
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16)&0x3f,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>10)&0x3f,
- status&0x1f, (status>>5)&0x3,
- le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3])>>16,
- d->ctx);
- else
- DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
- "%d ack=0x%X spd=%d data=0x%08X ctx=%d",
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])
- >>16)&0x3f,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
- >>4)&0xf,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
- >>10)&0x3f,
- status&0x1f, (status>>5)&0x3,
- le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]),
- d->ctx);
-#endif
-
- if (status & 0x10) {
- ack = status & 0xf;
- } else {
- switch (status & 0x1f) {
- case EVT_NO_STATUS: /* that should never happen */
- case EVT_RESERVED_A: /* that should never happen */
- case EVT_LONG_PACKET: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_MISSING_ACK:
- ack = ACKX_TIMEOUT;
- break;
- case EVT_UNDERRUN:
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_OVERRUN: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_DESCRIPTOR_READ:
- case EVT_DATA_READ:
- case EVT_DATA_WRITE:
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_BUS_RESET: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_TIMEOUT:
- ack = ACKX_TIMEOUT;
- break;
- case EVT_TCODE_ERR:
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_RESERVED_B: /* that should never happen */
- case EVT_RESERVED_C: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_UNKNOWN:
- case EVT_FLUSHED:
- ack = ACKX_SEND_ERROR;
- break;
- default:
- PRINT(KERN_ERR, "Unhandled OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- BUG();
- }
- }
-
- list_del_init(&packet->driver_list);
- hpsb_packet_sent(ohci->host, packet, ack);
-
- if (datasize)
- pci_unmap_single(ohci->dev,
- cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address),
- datasize, PCI_DMA_TODEVICE);
-
- d->sent_ind = (d->sent_ind+1)%d->num_desc;
- d->free_prgs++;
- }
-
- dma_trm_flush(ohci, d);
-
- spin_unlock_irqrestore(&d->lock, flags);
-}
-
-static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
-{
- int i;
- struct ti_ohci *ohci = d->ohci;
-
- if (ohci == NULL)
- return;
-
- DBGMSG("Freeing dma_rcv_ctx %d", d->ctx);
-
- if (d->buf_cpu) {
- for (i=0; i<d->num_desc; i++)
- if (d->buf_cpu[i] && d->buf_bus[i])
- pci_free_consistent(
- ohci->dev, d->buf_size,
- d->buf_cpu[i], d->buf_bus[i]);
- kfree(d->buf_cpu);
- kfree(d->buf_bus);
- }
- if (d->prg_cpu) {
- for (i=0; i<d->num_desc; i++)
- if (d->prg_cpu[i] && d->prg_bus[i])
- pci_pool_free(d->prg_pool, d->prg_cpu[i],
- d->prg_bus[i]);
- pci_pool_destroy(d->prg_pool);
- kfree(d->prg_cpu);
- kfree(d->prg_bus);
- }
- kfree(d->spb);
-
- /* Mark this context as freed. */
- d->ohci = NULL;
-}
-
-static int
-alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int buf_size, int split_buf_size, int context_base)
-{
- int i, len;
- static int num_allocs;
- static char pool_name[20];
-
- d->ohci = ohci;
- d->type = type;
- d->ctx = ctx;
-
- d->num_desc = num_desc;
- d->buf_size = buf_size;
- d->split_buf_size = split_buf_size;
-
- d->ctrlSet = 0;
- d->ctrlClear = 0;
- d->cmdPtr = 0;
-
- d->buf_cpu = kzalloc(d->num_desc * sizeof(*d->buf_cpu), GFP_ATOMIC);
- d->buf_bus = kzalloc(d->num_desc * sizeof(*d->buf_bus), GFP_ATOMIC);
-
- if (d->buf_cpu == NULL || d->buf_bus == NULL) {
- PRINT(KERN_ERR, "Failed to allocate %s", "DMA buffer");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
-
- d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_ATOMIC);
- d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_ATOMIC);
-
- if (d->prg_cpu == NULL || d->prg_bus == NULL) {
- PRINT(KERN_ERR, "Failed to allocate %s", "DMA prg");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
-
- d->spb = kmalloc(d->split_buf_size, GFP_ATOMIC);
-
- if (d->spb == NULL) {
- PRINT(KERN_ERR, "Failed to allocate %s", "split buffer");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
-
- len = sprintf(pool_name, "ohci1394_rcv_prg");
- sprintf(pool_name+len, "%d", num_allocs);
- d->prg_pool = pci_pool_create(pool_name, ohci->dev,
- sizeof(struct dma_cmd), 4, 0);
- if(d->prg_pool == NULL)
- {
- PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
- num_allocs++;
-
- for (i=0; i<d->num_desc; i++) {
- d->buf_cpu[i] = pci_alloc_consistent(ohci->dev,
- d->buf_size,
- d->buf_bus+i);
-
- if (d->buf_cpu[i] != NULL) {
- memset(d->buf_cpu[i], 0, d->buf_size);
- } else {
- PRINT(KERN_ERR,
- "Failed to allocate %s", "DMA buffer");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
-
- d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i);
-
- if (d->prg_cpu[i] != NULL) {
- memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd));
- } else {
- PRINT(KERN_ERR,
- "Failed to allocate %s", "DMA prg");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
- }
-
- spin_lock_init(&d->lock);
-
- d->ctrlSet = context_base + OHCI1394_ContextControlSet;
- d->ctrlClear = context_base + OHCI1394_ContextControlClear;
- d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
-
- tasklet_init(&d->task, dma_rcv_tasklet, (unsigned long) d);
- return 0;
-}
-
-static void free_dma_trm_ctx(struct dma_trm_ctx *d)
-{
- int i;
- struct ti_ohci *ohci = d->ohci;
-
- if (ohci == NULL)
- return;
-
- DBGMSG("Freeing dma_trm_ctx %d", d->ctx);
-
- if (d->prg_cpu) {
- for (i=0; i<d->num_desc; i++)
- if (d->prg_cpu[i] && d->prg_bus[i])
- pci_pool_free(d->prg_pool, d->prg_cpu[i],
- d->prg_bus[i]);
- pci_pool_destroy(d->prg_pool);
- kfree(d->prg_cpu);
- kfree(d->prg_bus);
- }
-
- /* Mark this context as freed. */
- d->ohci = NULL;
-}
-
-static int
-alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int context_base)
-{
- int i, len;
- static char pool_name[20];
- static int num_allocs=0;
-
- d->ohci = ohci;
- d->type = type;
- d->ctx = ctx;
- d->num_desc = num_desc;
- d->ctrlSet = 0;
- d->ctrlClear = 0;
- d->cmdPtr = 0;
-
- d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_KERNEL);
- d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_KERNEL);
-
- if (d->prg_cpu == NULL || d->prg_bus == NULL) {
- PRINT(KERN_ERR, "Failed to allocate %s", "AT DMA prg");
- free_dma_trm_ctx(d);
- return -ENOMEM;
- }
-
- len = sprintf(pool_name, "ohci1394_trm_prg");
- sprintf(pool_name+len, "%d", num_allocs);
- d->prg_pool = pci_pool_create(pool_name, ohci->dev,
- sizeof(struct at_dma_prg), 4, 0);
- if (d->prg_pool == NULL) {
- PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
- free_dma_trm_ctx(d);
- return -ENOMEM;
- }
- num_allocs++;
-
- for (i = 0; i < d->num_desc; i++) {
- d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i);
-
- if (d->prg_cpu[i] != NULL) {
- memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg));
- } else {
- PRINT(KERN_ERR,
- "Failed to allocate %s", "AT DMA prg");
- free_dma_trm_ctx(d);
- return -ENOMEM;
- }
- }
-
- spin_lock_init(&d->lock);
-
- /* initialize tasklet */
- d->ctrlSet = context_base + OHCI1394_ContextControlSet;
- d->ctrlClear = context_base + OHCI1394_ContextControlClear;
- d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
- tasklet_init(&d->task, dma_trm_tasklet, (unsigned long)d);
- return 0;
-}
-
-static void ohci_set_hw_config_rom(struct hpsb_host *host, __be32 *config_rom)
-{
- struct ti_ohci *ohci = host->hostdata;
-
- reg_write(ohci, OHCI1394_ConfigROMhdr, be32_to_cpu(config_rom[0]));
- reg_write(ohci, OHCI1394_BusOptions, be32_to_cpu(config_rom[2]));
-
- memcpy(ohci->csr_config_rom_cpu, config_rom, OHCI_CONFIG_ROM_LEN);
-}
-
-
-static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
- quadlet_t data, quadlet_t compare)
-{
- struct ti_ohci *ohci = host->hostdata;
- int i;
-
- reg_write(ohci, OHCI1394_CSRData, data);
- reg_write(ohci, OHCI1394_CSRCompareData, compare);
- reg_write(ohci, OHCI1394_CSRControl, reg & 0x3);
-
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
- break;
-
- mdelay(1);
- }
-
- return reg_read(ohci, OHCI1394_CSRData);
-}
-
-static struct hpsb_host_driver ohci1394_driver = {
- .owner = THIS_MODULE,
- .name = OHCI1394_DRIVER_NAME,
- .set_hw_config_rom = ohci_set_hw_config_rom,
- .transmit_packet = ohci_transmit,
- .devctl = ohci_devctl,
- .isoctl = ohci_isoctl,
- .hw_csr_reg = ohci_hw_csr_reg,
-};
-
-/***********************************
- * PCI Driver Interface functions *
- ***********************************/
-
-#ifdef CONFIG_PPC_PMAC
-static void ohci1394_pmac_on(struct pci_dev *dev)
-{
- if (machine_is(powermac)) {
- struct device_node *ofn = pci_device_to_OF_node(dev);
-
- if (ofn) {
- pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1);
- pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1);
- }
- }
-}
-
-static void ohci1394_pmac_off(struct pci_dev *dev)
-{
- if (machine_is(powermac)) {
- struct device_node *ofn = pci_device_to_OF_node(dev);
-
- if (ofn) {
- pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0);
- pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0);
- }
- }
-}
-#else
-#define ohci1394_pmac_on(dev)
-#define ohci1394_pmac_off(dev)
-#endif /* CONFIG_PPC_PMAC */
-
-static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- struct hpsb_host *host;
- struct ti_ohci *ohci; /* shortcut to currently handled device */
- resource_size_t ohci_base;
- int err = -ENOMEM;
-
- ohci1394_pmac_on(dev);
- if (pci_enable_device(dev)) {
- PRINT_G(KERN_ERR, "Failed to enable OHCI hardware");
- err = -ENXIO;
- goto err;
- }
- pci_set_master(dev);
-
- host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci), &dev->dev);
- if (!host) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "host structure");
- goto err;
- }
- ohci = host->hostdata;
- ohci->dev = dev;
- ohci->host = host;
- ohci->init_state = OHCI_INIT_ALLOC_HOST;
- host->pdev = dev;
- pci_set_drvdata(dev, ohci);
-
- /* We don't want hardware swapping */
- pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
-
- /* Some oddball Apple controllers do not order the selfid
- * properly, so we make up for it here. */
-#ifndef __LITTLE_ENDIAN
- /* XXX: Need a better way to check this. I'm wondering if we can
- * read the values of the OHCI1394_PCI_HCI_Control and the
- * noByteSwapData registers to see if they were not cleared to
- * zero. Should this work? Obviously it's not defined what these
- * registers will read when they aren't supported. Bleh! */
- if (dev->vendor == PCI_VENDOR_ID_APPLE &&
- dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
- ohci->no_swap_incoming = 1;
- ohci->selfid_swap = 0;
- } else
- ohci->selfid_swap = 1;
-#endif
-
-
-#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_FW
-#define PCI_DEVICE_ID_NVIDIA_NFORCE2_FW 0x006e
-#endif
-
- /* These chipsets require a bit of extra care when checking after
- * a busreset. */
- if ((dev->vendor == PCI_VENDOR_ID_APPLE &&
- dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) ||
- (dev->vendor == PCI_VENDOR_ID_NVIDIA &&
- dev->device == PCI_DEVICE_ID_NVIDIA_NFORCE2_FW))
- ohci->check_busreset = 1;
-
- /* We hardwire the MMIO length, since some CardBus adaptors
- * fail to report the right length. Anyway, the ohci spec
- * clearly says it's 2kb, so this shouldn't be a problem. */
- ohci_base = pci_resource_start(dev, 0);
- if (pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE)
- PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
- (unsigned long long)pci_resource_len(dev, 0));
-
- if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE,
- OHCI1394_DRIVER_NAME)) {
- PRINT_G(KERN_ERR, "MMIO resource (0x%llx - 0x%llx) unavailable",
- (unsigned long long)ohci_base,
- (unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
- goto err;
- }
- ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
-
- ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);
- if (ohci->registers == NULL) {
- PRINT_G(KERN_ERR, "Failed to remap registers");
- err = -ENXIO;
- goto err;
- }
- ohci->init_state = OHCI_INIT_HAVE_IOMAPPING;
- DBGMSG("Remapped memory spaces reg 0x%p", ohci->registers);
-
- /* csr_config rom allocation */
- ohci->csr_config_rom_cpu =
- pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
- &ohci->csr_config_rom_bus);
- if (ohci->csr_config_rom_cpu == NULL) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "buffer config rom");
- goto err;
- }
- ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER;
-
- /* self-id dma buffer allocation */
- ohci->selfid_buf_cpu =
- pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
- &ohci->selfid_buf_bus);
- if (ohci->selfid_buf_cpu == NULL) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "self-ID buffer");
- goto err;
- }
- ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER;
-
- if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)
- PRINT(KERN_INFO, "SelfID buffer %p is not aligned on "
- "8Kb boundary... may cause problems on some CXD3222 chip",
- ohci->selfid_buf_cpu);
-
- /* No self-id errors at startup */
- ohci->self_id_errors = 0;
-
- ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE;
- /* AR DMA request context allocation */
- if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context,
- DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
- AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
- OHCI1394_AsReqRcvContextBase) < 0) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Req context");
- goto err;
- }
- /* AR DMA response context allocation */
- if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context,
- DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,
- AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
- OHCI1394_AsRspRcvContextBase) < 0) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Resp context");
- goto err;
- }
- /* AT DMA request context */
- if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context,
- DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,
- OHCI1394_AsReqTrContextBase) < 0) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Req context");
- goto err;
- }
- /* AT DMA response context */
- if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context,
- DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,
- OHCI1394_AsRspTrContextBase) < 0) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Resp context");
- goto err;
- }
- /* Start off with a soft reset, to clear everything to a sane
- * state. */
- ohci_soft_reset(ohci);
-
- /* Now enable LPS, which we need in order to start accessing
- * most of the registers. In fact, on some cards (ALI M5251),
- * accessing registers in the SClk domain without LPS enabled
- * will lock up the machine. */
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
-
- /* Disable and clear interrupts */
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-
- /* Flush MMIO writes and wait to make sure we have full link enabled. */
- reg_read(ohci, OHCI1394_Version);
- msleep(50);
-
- /* Determine the number of available IR and IT contexts. */
- ohci->nb_iso_rcv_ctx =
- get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
- ohci->nb_iso_xmit_ctx =
- get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
-
- /* Set the usage bits for non-existent contexts so they can't
- * be allocated */
- ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx;
- ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx;
-
- INIT_LIST_HEAD(&ohci->iso_tasklet_list);
- spin_lock_init(&ohci->iso_tasklet_list_lock);
- ohci->ISO_channel_usage = 0;
- spin_lock_init(&ohci->IR_channel_lock);
-
- spin_lock_init(&ohci->event_lock);
-
- /*
- * interrupts are disabled, all right, but... due to IRQF_SHARED we
- * might get called anyway. We'll see no event, of course, but
- * we need to get to that "no event", so enough should be initialized
- * by that point.
- */
- err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
- OHCI1394_DRIVER_NAME, ohci);
- if (err) {
- PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq);
- goto err;
- }
- ohci->init_state = OHCI_INIT_HAVE_IRQ;
- ohci_initialize(ohci);
-
- /* Set certain csr values */
- host->csr.guid_hi = reg_read(ohci, OHCI1394_GUIDHi);
- host->csr.guid_lo = reg_read(ohci, OHCI1394_GUIDLo);
- host->csr.cyc_clk_acc = 100; /* how do we determine clk accuracy? */
- host->csr.max_rec = (reg_read(ohci, OHCI1394_BusOptions) >> 12) & 0xf;
- host->csr.lnk_spd = reg_read(ohci, OHCI1394_BusOptions) & 0x7;
-
- if (phys_dma) {
- host->low_addr_space =
- (u64) reg_read(ohci, OHCI1394_PhyUpperBound) << 16;
- if (!host->low_addr_space)
- host->low_addr_space = OHCI1394_PHYS_UPPER_BOUND_FIXED;
- }
- host->middle_addr_space = OHCI1394_MIDDLE_ADDRESS_SPACE;
-
- /* Tell the highlevel this host is ready */
- if (hpsb_add_host(host)) {
- PRINT_G(KERN_ERR, "Failed to register host with highlevel");
- goto err;
- }
- ohci->init_state = OHCI_INIT_DONE;
-
- return 0;
-err:
- ohci1394_pci_remove(dev);
- return err;
-}
-
-static void ohci1394_pci_remove(struct pci_dev *dev)
-{
- struct ti_ohci *ohci;
- struct device *device;
-
- ohci = pci_get_drvdata(dev);
- if (!ohci)
- goto out;
-
- device = get_device(&ohci->host->device);
-
- switch (ohci->init_state) {
- case OHCI_INIT_DONE:
- hpsb_remove_host(ohci->host);
-
- /* Clear out BUS Options */
- reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
- reg_write(ohci, OHCI1394_BusOptions,
- (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) |
- 0x00ff0000);
- memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN);
-
- case OHCI_INIT_HAVE_IRQ:
- /* Clear interrupt registers */
- reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-
- /* Disable IRM Contender */
- set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4));
-
- /* Clear link control register */
- reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-
- /* Let all other nodes know to ignore us */
- ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
-
- /* Soft reset before we start - this disables
- * interrupts and clears linkEnable and LPS. */
- ohci_soft_reset(ohci);
- free_irq(dev->irq, ohci);
-
- case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE:
- /* The ohci_soft_reset() stops all DMA contexts, so we
- * dont need to do this. */
- free_dma_rcv_ctx(&ohci->ar_req_context);
- free_dma_rcv_ctx(&ohci->ar_resp_context);
- free_dma_trm_ctx(&ohci->at_req_context);
- free_dma_trm_ctx(&ohci->at_resp_context);
-
- case OHCI_INIT_HAVE_SELFID_BUFFER:
- pci_free_consistent(dev, OHCI1394_SI_DMA_BUF_SIZE,
- ohci->selfid_buf_cpu,
- ohci->selfid_buf_bus);
-
- case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER:
- pci_free_consistent(dev, OHCI_CONFIG_ROM_LEN,
- ohci->csr_config_rom_cpu,
- ohci->csr_config_rom_bus);
-
- case OHCI_INIT_HAVE_IOMAPPING:
- iounmap(ohci->registers);
-
- case OHCI_INIT_HAVE_MEM_REGION:
- release_mem_region(pci_resource_start(dev, 0),
- OHCI1394_REGISTER_SIZE);
-
- case OHCI_INIT_ALLOC_HOST:
- pci_set_drvdata(dev, NULL);
- }
-
- if (device)
- put_device(device);
-out:
- ohci1394_pmac_off(dev);
-}
-
-#ifdef CONFIG_PM
-static int ohci1394_pci_suspend(struct pci_dev *dev, pm_message_t state)
-{
- int err;
- struct ti_ohci *ohci = pci_get_drvdata(dev);
-
- if (!ohci) {
- printk(KERN_ERR "%s: tried to suspend nonexisting host\n",
- OHCI1394_DRIVER_NAME);
- return -ENXIO;
- }
- DBGMSG("suspend called");
-
- /* Clear the async DMA contexts and stop using the controller */
- hpsb_bus_reset(ohci->host);
-
- /* See ohci1394_pci_remove() for comments on this sequence */
- reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
- reg_write(ohci, OHCI1394_BusOptions,
- (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) |
- 0x00ff0000);
- reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
- set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4));
- reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
- ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
- ohci_soft_reset(ohci);
-
- free_irq(dev->irq, ohci);
- err = pci_save_state(dev);
- if (err) {
- PRINT(KERN_ERR, "pci_save_state failed with %d", err);
- return err;
- }
- err = pci_set_power_state(dev, pci_choose_state(dev, state));
- if (err)
- DBGMSG("pci_set_power_state failed with %d", err);
- ohci1394_pmac_off(dev);
-
- return 0;
-}
-
-static int ohci1394_pci_resume(struct pci_dev *dev)
-{
- int err;
- struct ti_ohci *ohci = pci_get_drvdata(dev);
-
- if (!ohci) {
- printk(KERN_ERR "%s: tried to resume nonexisting host\n",
- OHCI1394_DRIVER_NAME);
- return -ENXIO;
- }
- DBGMSG("resume called");
-
- ohci1394_pmac_on(dev);
- pci_set_power_state(dev, PCI_D0);
- pci_restore_state(dev);
- err = pci_enable_device(dev);
- if (err) {
- PRINT(KERN_ERR, "pci_enable_device failed with %d", err);
- return err;
- }
-
- /* See ohci1394_pci_probe() for comments on this sequence */
- ohci_soft_reset(ohci);
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
- reg_read(ohci, OHCI1394_Version);
- msleep(50);
-
- err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
- OHCI1394_DRIVER_NAME, ohci);
- if (err) {
- PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq);
- return err;
- }
-
- ohci_initialize(ohci);
-
- hpsb_resume_host(ohci->host);
- return 0;
-}
-#endif /* CONFIG_PM */
-
-static struct pci_device_id ohci1394_pci_tbl[] = {
- {
- .class = PCI_CLASS_SERIAL_FIREWIRE_OHCI,
- .class_mask = PCI_ANY_ID,
- .vendor = PCI_ANY_ID,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
-
-static struct pci_driver ohci1394_pci_driver = {
- .name = OHCI1394_DRIVER_NAME,
- .id_table = ohci1394_pci_tbl,
- .probe = ohci1394_pci_probe,
- .remove = ohci1394_pci_remove,
-#ifdef CONFIG_PM
- .resume = ohci1394_pci_resume,
- .suspend = ohci1394_pci_suspend,
-#endif
-};
-
-/***********************************
- * OHCI1394 Video Interface *
- ***********************************/
-
-/* essentially the only purpose of this code is to allow another
- module to hook into ohci's interrupt handler */
-
-/* returns zero if successful, one if DMA context is locked up */
-int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
-{
- int i=0;
-
- /* stop the channel program if it's still running */
- reg_write(ohci, reg, 0x8000);
-
- /* Wait until it effectively stops */
- while (reg_read(ohci, reg) & 0x400) {
- i++;
- if (i>5000) {
- PRINT(KERN_ERR,
- "Runaway loop while stopping context: %s...", msg ? msg : "");
- return 1;
- }
-
- mb();
- udelay(10);
- }
- if (msg) PRINT(KERN_ERR, "%s: dma prg stopped", msg);
- return 0;
-}
-
-void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type,
- void (*func)(unsigned long), unsigned long data)
-{
- tasklet_init(&tasklet->tasklet, func, data);
- tasklet->type = type;
- /* We init the tasklet->link field, so we can list_del() it
- * without worrying whether it was added to the list or not. */
- INIT_LIST_HEAD(&tasklet->link);
-}
-
-int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
- struct ohci1394_iso_tasklet *tasklet)
-{
- unsigned long flags, *usage;
- int n, i, r = -EBUSY;
-
- if (tasklet->type == OHCI_ISO_TRANSMIT) {
- n = ohci->nb_iso_xmit_ctx;
- usage = &ohci->it_ctx_usage;
- }
- else {
- n = ohci->nb_iso_rcv_ctx;
- usage = &ohci->ir_ctx_usage;
-
- /* only one receive context can be multichannel (OHCI sec 10.4.1) */
- if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
- if (test_and_set_bit(0, &ohci->ir_multichannel_used)) {
- return r;
- }
- }
- }
-
- spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
- for (i = 0; i < n; i++)
- if (!test_and_set_bit(i, usage)) {
- tasklet->context = i;
- list_add_tail(&tasklet->link, &ohci->iso_tasklet_list);
- r = 0;
- break;
- }
-
- spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-
- return r;
-}
-
-void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
- struct ohci1394_iso_tasklet *tasklet)
-{
- unsigned long flags;
-
- tasklet_kill(&tasklet->tasklet);
-
- spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
- if (tasklet->type == OHCI_ISO_TRANSMIT)
- clear_bit(tasklet->context, &ohci->it_ctx_usage);
- else {
- clear_bit(tasklet->context, &ohci->ir_ctx_usage);
-
- if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
- clear_bit(0, &ohci->ir_multichannel_used);
- }
- }
-
- list_del(&tasklet->link);
-
- spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-}
-
-EXPORT_SYMBOL(ohci1394_stop_context);
-EXPORT_SYMBOL(ohci1394_init_iso_tasklet);
-EXPORT_SYMBOL(ohci1394_register_iso_tasklet);
-EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet);
-
-/***********************************
- * General module initialization *
- ***********************************/
-
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
-MODULE_LICENSE("GPL");
-
-static void __exit ohci1394_cleanup (void)
-{
- pci_unregister_driver(&ohci1394_pci_driver);
-}
-
-static int __init ohci1394_init(void)
-{
- return pci_register_driver(&ohci1394_pci_driver);
-}
-
-module_init(ohci1394_init);
-module_exit(ohci1394_cleanup);
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
deleted file mode 100644
index 7fb8ab9780ae..000000000000
--- a/drivers/ieee1394/ohci1394.h
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * ohci1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Gord Peters <GordPeters@smarttech.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _OHCI1394_H
-#define _OHCI1394_H
-
-#include "ieee1394_types.h"
-#include <asm/io.h>
-
-#define OHCI1394_DRIVER_NAME "ohci1394"
-
-#define OHCI1394_MAX_AT_REQ_RETRIES 0xf
-#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
-#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
-#define OHCI1394_MAX_SELF_ID_ERRORS 16
-
-#define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */
-#define AR_REQ_BUF_SIZE PAGE_SIZE /* size of AR req buffers */
-#define AR_REQ_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
-
-#define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */
-#define AR_RESP_BUF_SIZE PAGE_SIZE /* size of AR resp buffers */
-#define AR_RESP_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
-
-#define IR_NUM_DESC 16 /* number of IR descriptors */
-#define IR_BUF_SIZE PAGE_SIZE /* 4096 bytes/buffer */
-#define IR_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
-
-#define IT_NUM_DESC 16 /* number of IT descriptors */
-
-#define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */
-#define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */
-
-#define OHCI_LOOP_COUNT 100 /* Number of loops for reg read waits */
-
-#define OHCI_CONFIG_ROM_LEN 1024 /* Length of the mapped configrom space */
-
-#define OHCI1394_SI_DMA_BUF_SIZE 8192 /* length of the selfid buffer */
-
-/* PCI configuration space addresses */
-#define OHCI1394_PCI_HCI_Control 0x40
-
-struct dma_cmd {
- u32 control;
- u32 address;
- u32 branchAddress;
- u32 status;
-};
-
-/*
- * FIXME:
- * It is important that a single at_dma_prg does not cross a page boundary
- * The proper way to do it would be to do the check dynamically as the
- * programs are inserted into the AT fifo.
- */
-struct at_dma_prg {
- struct dma_cmd begin;
- quadlet_t data[4];
- struct dma_cmd end;
- quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
-};
-
-/* identify whether a DMA context is asynchronous or isochronous */
-enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO };
-
-/* DMA receive context */
-struct dma_rcv_ctx {
- struct ti_ohci *ohci;
- enum context_type type;
- int ctx;
- unsigned int num_desc;
-
- unsigned int buf_size;
- unsigned int split_buf_size;
-
- /* dma block descriptors */
- struct dma_cmd **prg_cpu;
- dma_addr_t *prg_bus;
- struct pci_pool *prg_pool;
-
- /* dma buffers */
- quadlet_t **buf_cpu;
- dma_addr_t *buf_bus;
-
- unsigned int buf_ind;
- unsigned int buf_offset;
- quadlet_t *spb;
- spinlock_t lock;
- struct tasklet_struct task;
- int ctrlClear;
- int ctrlSet;
- int cmdPtr;
- int ctxtMatch;
-};
-
-/* DMA transmit context */
-struct dma_trm_ctx {
- struct ti_ohci *ohci;
- enum context_type type;
- int ctx;
- unsigned int num_desc;
-
- /* dma block descriptors */
- struct at_dma_prg **prg_cpu;
- dma_addr_t *prg_bus;
- struct pci_pool *prg_pool;
-
- unsigned int prg_ind;
- unsigned int sent_ind;
- int free_prgs;
- quadlet_t *branchAddrPtr;
-
- /* list of packets inserted in the AT FIFO */
- struct list_head fifo_list;
-
- /* list of pending packets to be inserted in the AT FIFO */
- struct list_head pending_list;
-
- spinlock_t lock;
- struct tasklet_struct task;
- int ctrlClear;
- int ctrlSet;
- int cmdPtr;
-};
-
-struct ohci1394_iso_tasklet {
- struct tasklet_struct tasklet;
- struct list_head link;
- int context;
- enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE,
- OHCI_ISO_MULTICHANNEL_RECEIVE } type;
-};
-
-struct ti_ohci {
- struct pci_dev *dev;
-
- enum {
- OHCI_INIT_ALLOC_HOST,
- OHCI_INIT_HAVE_MEM_REGION,
- OHCI_INIT_HAVE_IOMAPPING,
- OHCI_INIT_HAVE_CONFIG_ROM_BUFFER,
- OHCI_INIT_HAVE_SELFID_BUFFER,
- OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE,
- OHCI_INIT_HAVE_IRQ,
- OHCI_INIT_DONE,
- } init_state;
-
- /* remapped memory spaces */
- void __iomem *registers;
-
- /* dma buffer for self-id packets */
- quadlet_t *selfid_buf_cpu;
- dma_addr_t selfid_buf_bus;
-
- /* buffer for csr config rom */
- quadlet_t *csr_config_rom_cpu;
- dma_addr_t csr_config_rom_bus;
- int csr_config_rom_length;
-
- unsigned int max_packet_size;
-
- /* async receive */
- struct dma_rcv_ctx ar_resp_context;
- struct dma_rcv_ctx ar_req_context;
-
- /* async transmit */
- struct dma_trm_ctx at_resp_context;
- struct dma_trm_ctx at_req_context;
-
- /* iso receive */
- int nb_iso_rcv_ctx;
- unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
- unsigned long ir_multichannel_used; /* ditto */
- spinlock_t IR_channel_lock;
-
- /* iso transmit */
- int nb_iso_xmit_ctx;
- unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
-
- u64 ISO_channel_usage;
-
- /* IEEE-1394 part follows */
- struct hpsb_host *host;
-
- int phyid, isroot;
-
- spinlock_t phy_reg_lock;
- spinlock_t event_lock;
-
- int self_id_errors;
-
- /* Tasklets for iso receive and transmit, used by video1394
- * and dv1394 */
- struct list_head iso_tasklet_list;
- spinlock_t iso_tasklet_list_lock;
-
- /* Swap the selfid buffer? */
- unsigned int selfid_swap:1;
- /* Some Apple chipset seem to swap incoming headers for us */
- unsigned int no_swap_incoming:1;
-
- /* Force extra paranoia checking on bus-reset handling */
- unsigned int check_busreset:1;
-};
-
-static inline int cross_bound(unsigned long addr, unsigned int size)
-{
- if (size == 0)
- return 0;
-
- if (size > PAGE_SIZE)
- return 1;
-
- if (addr >> PAGE_SHIFT != (addr + size - 1) >> PAGE_SHIFT)
- return 1;
-
- return 0;
-}
-
-/*
- * Register read and write helper functions.
- */
-static inline void reg_write(const struct ti_ohci *ohci, int offset, u32 data)
-{
- writel(data, ohci->registers + offset);
-}
-
-static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
-{
- return readl(ohci->registers + offset);
-}
-
-
-/* 2 KiloBytes of register space */
-#define OHCI1394_REGISTER_SIZE 0x800
-
-/* Offsets relative to context bases defined below */
-
-#define OHCI1394_ContextControlSet 0x000
-#define OHCI1394_ContextControlClear 0x004
-#define OHCI1394_ContextCommandPtr 0x00C
-
-/* register map */
-#define OHCI1394_Version 0x000
-#define OHCI1394_GUID_ROM 0x004
-#define OHCI1394_ATRetries 0x008
-#define OHCI1394_CSRData 0x00C
-#define OHCI1394_CSRCompareData 0x010
-#define OHCI1394_CSRControl 0x014
-#define OHCI1394_ConfigROMhdr 0x018
-#define OHCI1394_BusID 0x01C
-#define OHCI1394_BusOptions 0x020
-#define OHCI1394_GUIDHi 0x024
-#define OHCI1394_GUIDLo 0x028
-#define OHCI1394_ConfigROMmap 0x034
-#define OHCI1394_PostedWriteAddressLo 0x038
-#define OHCI1394_PostedWriteAddressHi 0x03C
-#define OHCI1394_VendorID 0x040
-#define OHCI1394_HCControlSet 0x050
-#define OHCI1394_HCControlClear 0x054
-#define OHCI1394_HCControl_noByteSwap 0x40000000
-#define OHCI1394_HCControl_programPhyEnable 0x00800000
-#define OHCI1394_HCControl_aPhyEnhanceEnable 0x00400000
-#define OHCI1394_HCControl_LPS 0x00080000
-#define OHCI1394_HCControl_postedWriteEnable 0x00040000
-#define OHCI1394_HCControl_linkEnable 0x00020000
-#define OHCI1394_HCControl_softReset 0x00010000
-#define OHCI1394_SelfIDBuffer 0x064
-#define OHCI1394_SelfIDCount 0x068
-#define OHCI1394_IRMultiChanMaskHiSet 0x070
-#define OHCI1394_IRMultiChanMaskHiClear 0x074
-#define OHCI1394_IRMultiChanMaskLoSet 0x078
-#define OHCI1394_IRMultiChanMaskLoClear 0x07C
-#define OHCI1394_IntEventSet 0x080
-#define OHCI1394_IntEventClear 0x084
-#define OHCI1394_IntMaskSet 0x088
-#define OHCI1394_IntMaskClear 0x08C
-#define OHCI1394_IsoXmitIntEventSet 0x090
-#define OHCI1394_IsoXmitIntEventClear 0x094
-#define OHCI1394_IsoXmitIntMaskSet 0x098
-#define OHCI1394_IsoXmitIntMaskClear 0x09C
-#define OHCI1394_IsoRecvIntEventSet 0x0A0
-#define OHCI1394_IsoRecvIntEventClear 0x0A4
-#define OHCI1394_IsoRecvIntMaskSet 0x0A8
-#define OHCI1394_IsoRecvIntMaskClear 0x0AC
-#define OHCI1394_InitialBandwidthAvailable 0x0B0
-#define OHCI1394_InitialChannelsAvailableHi 0x0B4
-#define OHCI1394_InitialChannelsAvailableLo 0x0B8
-#define OHCI1394_FairnessControl 0x0DC
-#define OHCI1394_LinkControlSet 0x0E0
-#define OHCI1394_LinkControlClear 0x0E4
-#define OHCI1394_LinkControl_RcvSelfID 0x00000200
-#define OHCI1394_LinkControl_RcvPhyPkt 0x00000400
-#define OHCI1394_LinkControl_CycleTimerEnable 0x00100000
-#define OHCI1394_LinkControl_CycleMaster 0x00200000
-#define OHCI1394_LinkControl_CycleSource 0x00400000
-#define OHCI1394_NodeID 0x0E8
-#define OHCI1394_PhyControl 0x0EC
-#define OHCI1394_IsochronousCycleTimer 0x0F0
-#define OHCI1394_AsReqFilterHiSet 0x100
-#define OHCI1394_AsReqFilterHiClear 0x104
-#define OHCI1394_AsReqFilterLoSet 0x108
-#define OHCI1394_AsReqFilterLoClear 0x10C
-#define OHCI1394_PhyReqFilterHiSet 0x110
-#define OHCI1394_PhyReqFilterHiClear 0x114
-#define OHCI1394_PhyReqFilterLoSet 0x118
-#define OHCI1394_PhyReqFilterLoClear 0x11C
-#define OHCI1394_PhyUpperBound 0x120
-
-#define OHCI1394_AsReqTrContextBase 0x180
-#define OHCI1394_AsReqTrContextControlSet 0x180
-#define OHCI1394_AsReqTrContextControlClear 0x184
-#define OHCI1394_AsReqTrCommandPtr 0x18C
-
-#define OHCI1394_AsRspTrContextBase 0x1A0
-#define OHCI1394_AsRspTrContextControlSet 0x1A0
-#define OHCI1394_AsRspTrContextControlClear 0x1A4
-#define OHCI1394_AsRspTrCommandPtr 0x1AC
-
-#define OHCI1394_AsReqRcvContextBase 0x1C0
-#define OHCI1394_AsReqRcvContextControlSet 0x1C0
-#define OHCI1394_AsReqRcvContextControlClear 0x1C4
-#define OHCI1394_AsReqRcvCommandPtr 0x1CC
-
-#define OHCI1394_AsRspRcvContextBase 0x1E0
-#define OHCI1394_AsRspRcvContextControlSet 0x1E0
-#define OHCI1394_AsRspRcvContextControlClear 0x1E4
-#define OHCI1394_AsRspRcvCommandPtr 0x1EC
-
-/* Isochronous transmit registers */
-/* Add (16 * n) for context n */
-#define OHCI1394_IsoXmitContextBase 0x200
-#define OHCI1394_IsoXmitContextControlSet 0x200
-#define OHCI1394_IsoXmitContextControlClear 0x204
-#define OHCI1394_IsoXmitCommandPtr 0x20C
-
-/* Isochronous receive registers */
-/* Add (32 * n) for context n */
-#define OHCI1394_IsoRcvContextBase 0x400
-#define OHCI1394_IsoRcvContextControlSet 0x400
-#define OHCI1394_IsoRcvContextControlClear 0x404
-#define OHCI1394_IsoRcvCommandPtr 0x40C
-#define OHCI1394_IsoRcvContextMatch 0x410
-
-/* Interrupts Mask/Events */
-
-#define OHCI1394_reqTxComplete 0x00000001
-#define OHCI1394_respTxComplete 0x00000002
-#define OHCI1394_ARRQ 0x00000004
-#define OHCI1394_ARRS 0x00000008
-#define OHCI1394_RQPkt 0x00000010
-#define OHCI1394_RSPkt 0x00000020
-#define OHCI1394_isochTx 0x00000040
-#define OHCI1394_isochRx 0x00000080
-#define OHCI1394_postedWriteErr 0x00000100
-#define OHCI1394_lockRespErr 0x00000200
-#define OHCI1394_selfIDComplete 0x00010000
-#define OHCI1394_busReset 0x00020000
-#define OHCI1394_phy 0x00080000
-#define OHCI1394_cycleSynch 0x00100000
-#define OHCI1394_cycle64Seconds 0x00200000
-#define OHCI1394_cycleLost 0x00400000
-#define OHCI1394_cycleInconsistent 0x00800000
-#define OHCI1394_unrecoverableError 0x01000000
-#define OHCI1394_cycleTooLong 0x02000000
-#define OHCI1394_phyRegRcvd 0x04000000
-#define OHCI1394_masterIntEnable 0x80000000
-
-/* DMA Control flags */
-#define DMA_CTL_OUTPUT_MORE 0x00000000
-#define DMA_CTL_OUTPUT_LAST 0x10000000
-#define DMA_CTL_INPUT_MORE 0x20000000
-#define DMA_CTL_INPUT_LAST 0x30000000
-#define DMA_CTL_UPDATE 0x08000000
-#define DMA_CTL_IMMEDIATE 0x02000000
-#define DMA_CTL_IRQ 0x00300000
-#define DMA_CTL_BRANCH 0x000c0000
-#define DMA_CTL_WAIT 0x00030000
-
-/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */
-#define EVT_NO_STATUS 0x0 /* No event status */
-#define EVT_RESERVED_A 0x1 /* Reserved, not used !!! */
-#define EVT_LONG_PACKET 0x2 /* The revc data was longer than the buf */
-#define EVT_MISSING_ACK 0x3 /* A subaction gap was detected before an ack
- arrived, or recv'd ack had a parity error */
-#define EVT_UNDERRUN 0x4 /* Underrun on corresponding FIFO, packet
- truncated */
-#define EVT_OVERRUN 0x5 /* A recv FIFO overflowed on reception of ISO
- packet */
-#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occurred while host was
- reading a descriptor block */
-#define EVT_DATA_READ 0x7 /* An error occurred while host controller was
- attempting to read from host memory in the data
- stage of descriptor processing */
-#define EVT_DATA_WRITE 0x8 /* An error occurred while host controller was
- attempting to write either during the data stage
- of descriptor processing, or when processing a single
- 16-bit host memory write */
-#define EVT_BUS_RESET 0x9 /* Identifies a PHY packet in the recv buffer as
- being a synthesized bus reset packet */
-#define EVT_TIMEOUT 0xa /* Indicates that the asynchronous transmit response
- packet expired and was not transmitted, or that an
- IT DMA context experienced a skip processing overflow */
-#define EVT_TCODE_ERR 0xb /* A bad tCode is associated with this packet.
- The packet was flushed */
-#define EVT_RESERVED_B 0xc /* Reserved, not used !!! */
-#define EVT_RESERVED_C 0xd /* Reserved, not used !!! */
-#define EVT_UNKNOWN 0xe /* An error condition has occurred that cannot be
- represented by any other event codes defined herein. */
-#define EVT_FLUSHED 0xf /* Send by the link side of output FIFO when asynchronous
- packets are being flushed due to a bus reset. */
-
-#define OHCI1394_TCODE_PHY 0xE
-
-/* Node offset map (phys DMA area, posted write area).
- * The value of OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED may be modified but must
- * be lower than OHCI1394_MIDDLE_ADDRESS_SPACE.
- * OHCI1394_PHYS_UPPER_BOUND_FIXED and OHCI1394_MIDDLE_ADDRESS_SPACE are
- * constants given by the OHCI spec.
- */
-#define OHCI1394_PHYS_UPPER_BOUND_FIXED 0x000100000000ULL /* 4 GB */
-#define OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED 0x010000000000ULL /* 1 TB */
-#define OHCI1394_MIDDLE_ADDRESS_SPACE 0xffff00000000ULL
-
-void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet,
- int type,
- void (*func)(unsigned long),
- unsigned long data);
-int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
- struct ohci1394_iso_tasklet *tasklet);
-void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
- struct ohci1394_iso_tasklet *tasklet);
-int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
-struct ti_ohci *ohci1394_get_struct(int card_num);
-
-#endif
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
deleted file mode 100644
index bf47fee79808..000000000000
--- a/drivers/ieee1394/pcilynx.c
+++ /dev/null
@@ -1,1554 +0,0 @@
-/*
- * pcilynx.c - Texas Instruments PCILynx driver
- * Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>,
- * Stephan Linz <linz@mazet.de>
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * 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.
- */
-
-/*
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * reading bus info block (containing GUID) from serial
- * eeprom via i2c and storing it in config ROM
- * Reworked code for initiating bus resets
- * (long, short, with or without hold-off)
- * Enhancements in async and iso send code
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/kdev_t.h>
-#include <linux/dma-mapping.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "pcilynx.h"
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
-/* print card specific information */
-#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
-#define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
-#else
-#define PRINT_GD(level, fmt, args...) do {} while (0)
-#define PRINTD(level, card, fmt, args...) do {} while (0)
-#endif
-
-
-/* Module Parameters */
-static int skip_eeprom;
-module_param(skip_eeprom, int, 0444);
-MODULE_PARM_DESC(skip_eeprom, "Use generic bus info block instead of serial eeprom (default = 0).");
-
-
-static struct hpsb_host_driver lynx_driver;
-static unsigned int card_id;
-
-
-
-/*
- * I2C stuff
- */
-
-/* the i2c stuff was inspired by i2c-philips-par.c */
-
-static void bit_setscl(void *data, int state)
-{
- if (state) {
- ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000040;
- } else {
- ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000040;
- }
- reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
-}
-
-static void bit_setsda(void *data, int state)
-{
- if (state) {
- ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000010;
- } else {
- ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000010;
- }
- reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
-}
-
-static int bit_getscl(void *data)
-{
- return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000040;
-}
-
-static int bit_getsda(void *data)
-{
- return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010;
-}
-
-static struct i2c_algo_bit_data bit_data = {
- .setsda = bit_setsda,
- .setscl = bit_setscl,
- .getsda = bit_getsda,
- .getscl = bit_getscl,
- .udelay = 5,
- .timeout = 100,
-};
-
-
-/*
- * PCL handling functions.
- */
-
-static pcl_t alloc_pcl(struct ti_lynx *lynx)
-{
- u8 m;
- int i, j;
-
- spin_lock(&lynx->lock);
- /* FIXME - use ffz() to make this readable */
- for (i = 0; i < (LOCALRAM_SIZE / 1024); i++) {
- m = lynx->pcl_bmap[i];
- for (j = 0; j < 8; j++) {
- if (m & 1<<j) {
- continue;
- }
- m |= 1<<j;
- lynx->pcl_bmap[i] = m;
- spin_unlock(&lynx->lock);
- return 8 * i + j;
- }
- }
- spin_unlock(&lynx->lock);
-
- return -1;
-}
-
-
-#if 0
-static void free_pcl(struct ti_lynx *lynx, pcl_t pclid)
-{
- int off, bit;
-
- off = pclid / 8;
- bit = pclid % 8;
-
- if (pclid < 0) {
- return;
- }
-
- spin_lock(&lynx->lock);
- if (lynx->pcl_bmap[off] & 1<<bit) {
- lynx->pcl_bmap[off] &= ~(1<<bit);
- } else {
- PRINT(KERN_ERR, lynx->id,
- "attempted to free unallocated PCL %d", pclid);
- }
- spin_unlock(&lynx->lock);
-}
-
-/* functions useful for debugging */
-static void pretty_print_pcl(const struct ti_pcl *pcl)
-{
- int i;
-
- printk("PCL next %08x, userdata %08x, status %08x, remtrans %08x, nextbuf %08x\n",
- pcl->next, pcl->user_data, pcl->pcl_status,
- pcl->remaining_transfer_count, pcl->next_data_buffer);
-
- printk("PCL");
- for (i=0; i<13; i++) {
- printk(" c%x:%08x d%x:%08x",
- i, pcl->buffer[i].control, i, pcl->buffer[i].pointer);
- if (!(i & 0x3) && (i != 12)) printk("\nPCL");
- }
- printk("\n");
-}
-
-static void print_pcl(const struct ti_lynx *lynx, pcl_t pclid)
-{
- struct ti_pcl pcl;
-
- get_pcl(lynx, pclid, &pcl);
- pretty_print_pcl(&pcl);
-}
-#endif
-
-
-
-/***********************************
- * IEEE-1394 functionality section *
- ***********************************/
-
-
-static int get_phy_reg(struct ti_lynx *lynx, int addr)
-{
- int retval;
- int i = 0;
-
- unsigned long flags;
-
- if (addr > 15) {
- PRINT(KERN_ERR, lynx->id,
- "%s: PHY register address %d out of range",
- __func__, addr);
- return -1;
- }
-
- spin_lock_irqsave(&lynx->phy_reg_lock, flags);
-
- reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr));
- do {
- retval = reg_read(lynx, LINK_PHY);
-
- if (i > 10000) {
- PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting",
- __func__);
- retval = -1;
- break;
- }
- i++;
- } while ((retval & 0xf00) != LINK_PHY_RADDR(addr));
-
- reg_write(lynx, LINK_INT_STATUS, LINK_INT_PHY_REG_RCVD);
- spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
-
- if (retval != -1) {
- return retval & 0xff;
- } else {
- return -1;
- }
-}
-
-static int set_phy_reg(struct ti_lynx *lynx, int addr, int val)
-{
- unsigned long flags;
-
- if (addr > 15) {
- PRINT(KERN_ERR, lynx->id,
- "%s: PHY register address %d out of range", __func__, addr);
- return -1;
- }
-
- if (val > 0xff) {
- PRINT(KERN_ERR, lynx->id,
- "%s: PHY register value %d out of range", __func__, val);
- return -1;
- }
-
- spin_lock_irqsave(&lynx->phy_reg_lock, flags);
-
- reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(addr)
- | LINK_PHY_WDATA(val));
-
- spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
-
- return 0;
-}
-
-static int sel_phy_reg_page(struct ti_lynx *lynx, int page)
-{
- int reg;
-
- if (page > 7) {
- PRINT(KERN_ERR, lynx->id,
- "%s: PHY page %d out of range", __func__, page);
- return -1;
- }
-
- reg = get_phy_reg(lynx, 7);
- if (reg != -1) {
- reg &= 0x1f;
- reg |= (page << 5);
- set_phy_reg(lynx, 7, reg);
- return 0;
- } else {
- return -1;
- }
-}
-
-#if 0 /* not needed at this time */
-static int sel_phy_reg_port(struct ti_lynx *lynx, int port)
-{
- int reg;
-
- if (port > 15) {
- PRINT(KERN_ERR, lynx->id,
- "%s: PHY port %d out of range", __func__, port);
- return -1;
- }
-
- reg = get_phy_reg(lynx, 7);
- if (reg != -1) {
- reg &= 0xf0;
- reg |= port;
- set_phy_reg(lynx, 7, reg);
- return 0;
- } else {
- return -1;
- }
-}
-#endif
-
-static u32 get_phy_vendorid(struct ti_lynx *lynx)
-{
- u32 pvid = 0;
- sel_phy_reg_page(lynx, 1);
- pvid |= (get_phy_reg(lynx, 10) << 16);
- pvid |= (get_phy_reg(lynx, 11) << 8);
- pvid |= get_phy_reg(lynx, 12);
- PRINT(KERN_INFO, lynx->id, "PHY vendor id 0x%06x", pvid);
- return pvid;
-}
-
-static u32 get_phy_productid(struct ti_lynx *lynx)
-{
- u32 id = 0;
- sel_phy_reg_page(lynx, 1);
- id |= (get_phy_reg(lynx, 13) << 16);
- id |= (get_phy_reg(lynx, 14) << 8);
- id |= get_phy_reg(lynx, 15);
- PRINT(KERN_INFO, lynx->id, "PHY product id 0x%06x", id);
- return id;
-}
-
-static quadlet_t generate_own_selfid(struct ti_lynx *lynx,
- struct hpsb_host *host)
-{
- quadlet_t lsid;
- char phyreg[7];
- int i;
-
- phyreg[0] = lynx->phy_reg0;
- for (i = 1; i < 7; i++) {
- phyreg[i] = get_phy_reg(lynx, i);
- }
-
- /* FIXME? We assume a TSB21LV03A phy here. This code doesn't support
- more than 3 ports on the PHY anyway. */
-
- lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22);
- lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */
- lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */
- if (!hpsb_disable_irm)
- lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */
- /* lsid |= 1 << 11; *//* set contender (hack) */
- lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */
-
- for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */
- if (phyreg[3 + i] & 0x4) {
- lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3)
- << (6 - i*2);
- } else {
- lsid |= 1 << (6 - i*2);
- }
- }
-
- cpu_to_be32s(&lsid);
- PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid);
- return lsid;
-}
-
-static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host)
-{
- quadlet_t *q = lynx->rcv_page;
- int phyid, isroot, size;
- quadlet_t lsid = 0;
- int i;
-
- if (lynx->phy_reg0 == -1 || lynx->selfid_size == -1) return;
-
- size = lynx->selfid_size;
- phyid = lynx->phy_reg0;
-
- i = (size > 16 ? 16 : size) / 4 - 1;
- while (i >= 0) {
- cpu_to_be32s(&q[i]);
- i--;
- }
-
- if (!lynx->phyic.reg_1394a) {
- lsid = generate_own_selfid(lynx, host);
- }
-
- isroot = (phyid & 2) != 0;
- phyid >>= 2;
- PRINT(KERN_INFO, lynx->id, "SelfID process finished (phyid %d, %s)",
- phyid, (isroot ? "root" : "not root"));
- reg_write(lynx, LINK_ID, (0xffc0 | phyid) << 16);
-
- if (!lynx->phyic.reg_1394a && !size) {
- hpsb_selfid_received(host, lsid);
- }
-
- while (size > 0) {
- struct selfid *sid = (struct selfid *)q;
-
- if (!lynx->phyic.reg_1394a && !sid->extended
- && (sid->phy_id == (phyid + 1))) {
- hpsb_selfid_received(host, lsid);
- }
-
- if (q[0] == ~q[1]) {
- PRINT(KERN_DEBUG, lynx->id, "SelfID packet 0x%x rcvd",
- q[0]);
- hpsb_selfid_received(host, q[0]);
- } else {
- PRINT(KERN_INFO, lynx->id,
- "inconsistent selfid 0x%x/0x%x", q[0], q[1]);
- }
- q += 2;
- size -= 8;
- }
-
- if (!lynx->phyic.reg_1394a && isroot && phyid != 0) {
- hpsb_selfid_received(host, lsid);
- }
-
- hpsb_selfid_complete(host, phyid, isroot);
-
- if (host->in_bus_reset) return; /* in bus reset again */
-
- if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); //FIXME: I do not think, we need this here
- reg_set_bits(lynx, LINK_CONTROL,
- LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN
- | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN);
-}
-
-
-
-/* This must be called with the respective queue_lock held. */
-static void send_next(struct ti_lynx *lynx, int what)
-{
- struct ti_pcl pcl;
- struct lynx_send_data *d;
- struct hpsb_packet *packet;
-
-#if 0 /* has been removed from ieee1394 core */
- d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async);
-#else
- d = &lynx->async;
-#endif
- if (!list_empty(&d->pcl_queue)) {
- PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo");
- BUG();
- }
-
- packet = driver_packet(d->queue.next);
- list_move_tail(&packet->driver_list, &d->pcl_queue);
-
- d->header_dma = pci_map_single(lynx->dev, packet->header,
- packet->header_size, PCI_DMA_TODEVICE);
- if (packet->data_size) {
- d->data_dma = pci_map_single(lynx->dev, packet->data,
- packet->data_size,
- PCI_DMA_TODEVICE);
- } else {
- d->data_dma = 0;
- }
-
- pcl.next = PCL_NEXT_INVALID;
- pcl.async_error_next = PCL_NEXT_INVALID;
- pcl.pcl_status = 0;
- pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size;
-#ifndef __BIG_ENDIAN
- pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
- pcl.buffer[0].pointer = d->header_dma;
- pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size;
- pcl.buffer[1].pointer = d->data_dma;
-
- switch (packet->type) {
- case hpsb_async:
- pcl.buffer[0].control |= PCL_CMD_XMT;
- break;
-#if 0 /* has been removed from ieee1394 core */
- case hpsb_iso:
- pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE;
- break;
-#endif
- case hpsb_raw:
- pcl.buffer[0].control |= PCL_CMD_UNFXMT;
- break;
- }
-
- put_pcl(lynx, d->pcl, &pcl);
- run_pcl(lynx, d->pcl_start, d->channel);
-}
-
-
-/* called from subsystem core */
-static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
-{
- struct ti_lynx *lynx = host->hostdata;
- struct lynx_send_data *d;
- unsigned long flags;
-
- if (packet->data_size >= 4096) {
- PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%Zd)",
- packet->data_size);
- return -EOVERFLOW;
- }
-
- switch (packet->type) {
- case hpsb_async:
- case hpsb_raw:
- d = &lynx->async;
- break;
-#if 0 /* has been removed from ieee1394 core */
- case hpsb_iso:
- d = &lynx->iso_send;
- break;
-#endif
- default:
- PRINT(KERN_ERR, lynx->id, "invalid packet type %d",
- packet->type);
- return -EINVAL;
- }
-
- if (packet->tcode == TCODE_WRITEQ
- || packet->tcode == TCODE_READQ_RESPONSE) {
- cpu_to_be32s(&packet->header[3]);
- }
-
- spin_lock_irqsave(&d->queue_lock, flags);
-
- list_add_tail(&packet->driver_list, &d->queue);
- if (list_empty(&d->pcl_queue))
- send_next(lynx, packet->type);
-
- spin_unlock_irqrestore(&d->queue_lock, flags);
-
- return 0;
-}
-
-
-/* called from subsystem core */
-static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
-{
- struct ti_lynx *lynx = host->hostdata;
- int retval = 0;
- struct hpsb_packet *packet;
- LIST_HEAD(packet_list);
- unsigned long flags;
- int phy_reg;
-
- switch (cmd) {
- case RESET_BUS:
- if (reg_read(lynx, LINK_INT_STATUS) & LINK_INT_PHY_BUSRESET) {
- retval = 0;
- break;
- }
-
- switch (arg) {
- case SHORT_RESET:
- if (lynx->phyic.reg_1394a) {
- phy_reg = get_phy_reg(lynx, 5);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg |= 0x40;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
- break;
- } else {
- PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
- /* fall through to long bus reset */
- }
- case LONG_RESET:
- phy_reg = get_phy_reg(lynx, 1);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg |= 0x40;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */
- break;
- case SHORT_RESET_NO_FORCE_ROOT:
- if (lynx->phyic.reg_1394a) {
- phy_reg = get_phy_reg(lynx, 1);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- if (phy_reg & 0x80) {
- phy_reg &= ~0x80;
- set_phy_reg(lynx, 1, phy_reg); /* clear RHB */
- }
-
- phy_reg = get_phy_reg(lynx, 5);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg |= 0x40;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, no force_root) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
- break;
- } else {
- PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
- /* fall through to long bus reset */
- }
- case LONG_RESET_NO_FORCE_ROOT:
- phy_reg = get_phy_reg(lynx, 1);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg &= ~0x80;
- phy_reg |= 0x40;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, no force_root) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */
- break;
- case SHORT_RESET_FORCE_ROOT:
- if (lynx->phyic.reg_1394a) {
- phy_reg = get_phy_reg(lynx, 1);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- if (!(phy_reg & 0x80)) {
- phy_reg |= 0x80;
- set_phy_reg(lynx, 1, phy_reg); /* set RHB */
- }
-
- phy_reg = get_phy_reg(lynx, 5);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg |= 0x40;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, force_root set) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
- break;
- } else {
- PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
- /* fall through to long bus reset */
- }
- case LONG_RESET_FORCE_ROOT:
- phy_reg = get_phy_reg(lynx, 1);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg |= 0xc0;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, force_root set) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 1, phy_reg); /* set IBR and RHB */
- break;
- default:
- PRINT(KERN_ERR, lynx->id, "unknown argument for reset_bus command %d", arg);
- retval = -1;
- }
-
- break;
-
- case GET_CYCLE_COUNTER:
- retval = reg_read(lynx, CYCLE_TIMER);
- break;
-
- case SET_CYCLE_COUNTER:
- reg_write(lynx, CYCLE_TIMER, arg);
- break;
-
- case SET_BUS_ID:
- reg_write(lynx, LINK_ID,
- (arg << 22) | (reg_read(lynx, LINK_ID) & 0x003f0000));
- break;
-
- case ACT_CYCLE_MASTER:
- if (arg) {
- reg_set_bits(lynx, LINK_CONTROL,
- LINK_CONTROL_CYCMASTER);
- } else {
- reg_clear_bits(lynx, LINK_CONTROL,
- LINK_CONTROL_CYCMASTER);
- }
- break;
-
- case CANCEL_REQUESTS:
- spin_lock_irqsave(&lynx->async.queue_lock, flags);
-
- reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0);
- list_splice_init(&lynx->async.queue, &packet_list);
-
- if (list_empty(&lynx->async.pcl_queue)) {
- spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
- PRINTD(KERN_DEBUG, lynx->id, "no async packet in PCL to cancel");
- } else {
- struct ti_pcl pcl;
- u32 ack;
-
- PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL");
-
- get_pcl(lynx, lynx->async.pcl, &pcl);
-
- packet = driver_packet(lynx->async.pcl_queue.next);
- list_del_init(&packet->driver_list);
-
- pci_unmap_single(lynx->dev, lynx->async.header_dma,
- packet->header_size, PCI_DMA_TODEVICE);
- if (packet->data_size) {
- pci_unmap_single(lynx->dev, lynx->async.data_dma,
- packet->data_size, PCI_DMA_TODEVICE);
- }
-
- spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
-
- if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
- if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
- ack = (pcl.pcl_status >> 15) & 0xf;
- PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
- ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
- } else {
- ack = (pcl.pcl_status >> 15) & 0xf;
- }
- } else {
- PRINT(KERN_INFO, lynx->id, "async packet was not completed");
- ack = ACKX_ABORTED;
- }
- hpsb_packet_sent(host, packet, ack);
- }
-
- while (!list_empty(&packet_list)) {
- packet = driver_packet(packet_list.next);
- list_del_init(&packet->driver_list);
- hpsb_packet_sent(host, packet, ACKX_ABORTED);
- }
-
- break;
-#if 0 /* has been removed from ieee1394 core */
- case ISO_LISTEN_CHANNEL:
- spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
- if (lynx->iso_rcv.chan_count++ == 0) {
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
- DMA_WORD1_CMP_ENABLE_MASTER);
- }
-
- spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
- break;
-
- case ISO_UNLISTEN_CHANNEL:
- spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
- if (--lynx->iso_rcv.chan_count == 0) {
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
- 0);
- }
-
- spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
- break;
-#endif
- default:
- PRINT(KERN_ERR, lynx->id, "unknown devctl command %d", cmd);
- retval = -1;
- }
-
- return retval;
-}
-
-
-/***************************************
- * IEEE-1394 functionality section END *
- ***************************************/
-
-
-/********************************************************
- * Global stuff (interrupt handler, init/shutdown code) *
- ********************************************************/
-
-
-static irqreturn_t lynx_irq_handler(int irq, void *dev_id)
-{
- struct ti_lynx *lynx = (struct ti_lynx *)dev_id;
- struct hpsb_host *host = lynx->host;
- u32 intmask;
- u32 linkint;
-
- linkint = reg_read(lynx, LINK_INT_STATUS);
- intmask = reg_read(lynx, PCI_INT_STATUS);
-
- if (!(intmask & PCI_INT_INT_PEND))
- return IRQ_NONE;
-
- PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask,
- linkint);
-
- reg_write(lynx, LINK_INT_STATUS, linkint);
- reg_write(lynx, PCI_INT_STATUS, intmask);
-
- if (intmask & PCI_INT_1394) {
- if (linkint & LINK_INT_PHY_TIMEOUT) {
- PRINT(KERN_INFO, lynx->id, "PHY timeout occurred");
- }
- if (linkint & LINK_INT_PHY_BUSRESET) {
- PRINT(KERN_INFO, lynx->id, "bus reset interrupt");
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- if (!host->in_bus_reset)
- hpsb_bus_reset(host);
- }
- if (linkint & LINK_INT_PHY_REG_RCVD) {
- u32 reg;
-
- spin_lock(&lynx->phy_reg_lock);
- reg = reg_read(lynx, LINK_PHY);
- spin_unlock(&lynx->phy_reg_lock);
-
- if (!host->in_bus_reset) {
- PRINT(KERN_INFO, lynx->id,
- "phy reg received without reset");
- } else if (reg & 0xf00) {
- PRINT(KERN_INFO, lynx->id,
- "unsolicited phy reg %d received",
- (reg >> 8) & 0xf);
- } else {
- lynx->phy_reg0 = reg & 0xff;
- handle_selfid(lynx, host);
- }
- }
- if (linkint & LINK_INT_ISO_STUCK) {
- PRINT(KERN_INFO, lynx->id, "isochronous transmitter stuck");
- }
- if (linkint & LINK_INT_ASYNC_STUCK) {
- PRINT(KERN_INFO, lynx->id, "asynchronous transmitter stuck");
- }
- if (linkint & LINK_INT_SENT_REJECT) {
- PRINT(KERN_INFO, lynx->id, "sent reject");
- }
- if (linkint & LINK_INT_TX_INVALID_TC) {
- PRINT(KERN_INFO, lynx->id, "invalid transaction code");
- }
- if (linkint & LINK_INT_GRF_OVERFLOW) {
- /* flush FIFO if overflow happens during reset */
- if (host->in_bus_reset)
- reg_write(lynx, FIFO_CONTROL,
- FIFO_CONTROL_GRF_FLUSH);
- PRINT(KERN_INFO, lynx->id, "GRF overflow");
- }
- if (linkint & LINK_INT_ITF_UNDERFLOW) {
- PRINT(KERN_INFO, lynx->id, "ITF underflow");
- }
- if (linkint & LINK_INT_ATF_UNDERFLOW) {
- PRINT(KERN_INFO, lynx->id, "ATF underflow");
- }
- }
-
- if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) {
- PRINTD(KERN_DEBUG, lynx->id, "iso receive");
-
- spin_lock(&lynx->iso_rcv.lock);
-
- lynx->iso_rcv.stat[lynx->iso_rcv.next] =
- reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ISO_RCV));
-
- lynx->iso_rcv.used++;
- lynx->iso_rcv.next = (lynx->iso_rcv.next + 1) % NUM_ISORCV_PCL;
-
- if ((lynx->iso_rcv.next == lynx->iso_rcv.last)
- || !lynx->iso_rcv.chan_count) {
- PRINTD(KERN_DEBUG, lynx->id, "stopped");
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
- }
-
- run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, lynx->iso_rcv.next,
- CHANNEL_ISO_RCV);
-
- spin_unlock(&lynx->iso_rcv.lock);
-
- tasklet_schedule(&lynx->iso_rcv.tq);
- }
-
- if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) {
- PRINTD(KERN_DEBUG, lynx->id, "async sent");
- spin_lock(&lynx->async.queue_lock);
-
- if (list_empty(&lynx->async.pcl_queue)) {
- spin_unlock(&lynx->async.queue_lock);
- PRINT(KERN_WARNING, lynx->id, "async dma halted, but no queued packet (maybe it was cancelled)");
- } else {
- struct ti_pcl pcl;
- u32 ack;
- struct hpsb_packet *packet;
-
- get_pcl(lynx, lynx->async.pcl, &pcl);
-
- packet = driver_packet(lynx->async.pcl_queue.next);
- list_del_init(&packet->driver_list);
-
- pci_unmap_single(lynx->dev, lynx->async.header_dma,
- packet->header_size, PCI_DMA_TODEVICE);
- if (packet->data_size) {
- pci_unmap_single(lynx->dev, lynx->async.data_dma,
- packet->data_size, PCI_DMA_TODEVICE);
- }
-
- if (!list_empty(&lynx->async.queue)) {
- send_next(lynx, hpsb_async);
- }
-
- spin_unlock(&lynx->async.queue_lock);
-
- if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
- if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
- ack = (pcl.pcl_status >> 15) & 0xf;
- PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
- ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
- } else {
- ack = (pcl.pcl_status >> 15) & 0xf;
- }
- } else {
- PRINT(KERN_INFO, lynx->id, "async packet was not completed");
- ack = ACKX_SEND_ERROR;
- }
- hpsb_packet_sent(host, packet, ack);
- }
- }
-
- if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) {
- PRINTD(KERN_DEBUG, lynx->id, "iso sent");
- spin_lock(&lynx->iso_send.queue_lock);
-
- if (list_empty(&lynx->iso_send.pcl_queue)) {
- spin_unlock(&lynx->iso_send.queue_lock);
- PRINT(KERN_ERR, lynx->id, "iso send dma halted, but no queued packet");
- } else {
- struct ti_pcl pcl;
- u32 ack;
- struct hpsb_packet *packet;
-
- get_pcl(lynx, lynx->iso_send.pcl, &pcl);
-
- packet = driver_packet(lynx->iso_send.pcl_queue.next);
- list_del_init(&packet->driver_list);
-
- pci_unmap_single(lynx->dev, lynx->iso_send.header_dma,
- packet->header_size, PCI_DMA_TODEVICE);
- if (packet->data_size) {
- pci_unmap_single(lynx->dev, lynx->iso_send.data_dma,
- packet->data_size, PCI_DMA_TODEVICE);
- }
-#if 0 /* has been removed from ieee1394 core */
- if (!list_empty(&lynx->iso_send.queue)) {
- send_next(lynx, hpsb_iso);
- }
-#endif
- spin_unlock(&lynx->iso_send.queue_lock);
-
- if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
- if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
- ack = (pcl.pcl_status >> 15) & 0xf;
- PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
- ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
- } else {
- ack = (pcl.pcl_status >> 15) & 0xf;
- }
- } else {
- PRINT(KERN_INFO, lynx->id, "iso send packet was not completed");
- ack = ACKX_SEND_ERROR;
- }
-
- hpsb_packet_sent(host, packet, ack); //FIXME: maybe we should just use ACK_COMPLETE and ACKX_SEND_ERROR
- }
- }
-
- if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) {
- /* general receive DMA completed */
- int stat = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_RCV));
-
- PRINTD(KERN_DEBUG, lynx->id, "received packet size %d",
- stat & 0x1fff);
-
- if (stat & DMA_CHAN_STAT_SELFID) {
- lynx->selfid_size = stat & 0x1fff;
- handle_selfid(lynx, host);
- } else {
- quadlet_t *q_data = lynx->rcv_page;
- if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE
- || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) {
- cpu_to_be32s(q_data + 3);
- }
- hpsb_packet_received(host, q_data, stat & 0x1fff, 0);
- }
-
- run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
- }
-
- return IRQ_HANDLED;
-}
-
-
-static void iso_rcv_bh(struct ti_lynx *lynx)
-{
- unsigned int idx;
- quadlet_t *data;
- unsigned long flags;
-
- spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
- while (lynx->iso_rcv.used) {
- idx = lynx->iso_rcv.last;
- spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-
- data = lynx->iso_rcv.page[idx / ISORCV_PER_PAGE]
- + (idx % ISORCV_PER_PAGE) * MAX_ISORCV_SIZE;
-
- if ((*data >> 16) + 4 != (lynx->iso_rcv.stat[idx] & 0x1fff)) {
- PRINT(KERN_ERR, lynx->id,
- "iso length mismatch 0x%08x/0x%08x", *data,
- lynx->iso_rcv.stat[idx]);
- }
-
- if (lynx->iso_rcv.stat[idx]
- & (DMA_CHAN_STAT_PCIERR | DMA_CHAN_STAT_PKTERR)) {
- PRINT(KERN_INFO, lynx->id,
- "iso receive error on %d to 0x%p", idx, data);
- } else {
- hpsb_packet_received(lynx->host, data,
- lynx->iso_rcv.stat[idx] & 0x1fff,
- 0);
- }
-
- spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
- lynx->iso_rcv.last = (idx + 1) % NUM_ISORCV_PCL;
- lynx->iso_rcv.used--;
- }
-
- if (lynx->iso_rcv.chan_count) {
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
- DMA_WORD1_CMP_ENABLE_MASTER);
- }
- spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-}
-
-
-static void remove_card(struct pci_dev *dev)
-{
- struct ti_lynx *lynx;
- struct device *lynx_dev;
- int i;
-
- lynx = pci_get_drvdata(dev);
- if (!lynx) return;
- pci_set_drvdata(dev, NULL);
-
- lynx_dev = get_device(&lynx->host->device);
-
- switch (lynx->state) {
- case is_host:
- reg_write(lynx, PCI_INT_ENABLE, 0);
- hpsb_remove_host(lynx->host);
- case have_intr:
- reg_write(lynx, PCI_INT_ENABLE, 0);
- free_irq(lynx->dev->irq, lynx);
-
- /* Disable IRM Contender and LCtrl */
- if (lynx->phyic.reg_1394a)
- set_phy_reg(lynx, 4, ~0xc0 & get_phy_reg(lynx, 4));
-
- /* Let all other nodes know to ignore us */
- lynx_devctl(lynx->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
-
- case have_iomappings:
- reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
- /* Fix buggy cards with autoboot pin not tied low: */
- reg_write(lynx, DMA0_CHAN_CTRL, 0);
- iounmap(lynx->registers);
- iounmap(lynx->local_rom);
- iounmap(lynx->local_ram);
- iounmap(lynx->aux_port);
- case have_1394_buffers:
- for (i = 0; i < ISORCV_PAGES; i++) {
- if (lynx->iso_rcv.page[i]) {
- pci_free_consistent(lynx->dev, PAGE_SIZE,
- lynx->iso_rcv.page[i],
- lynx->iso_rcv.page_dma[i]);
- }
- }
- pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
- lynx->rcv_page_dma);
- case have_aux_buf:
- case have_pcl_mem:
- pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
- lynx->pcl_mem_dma);
- case clear:
- /* do nothing - already freed */
- ;
- }
-
- tasklet_kill(&lynx->iso_rcv.tq);
-
- if (lynx_dev)
- put_device(lynx_dev);
-}
-
-
-static int __devinit add_card(struct pci_dev *dev,
- const struct pci_device_id *devid_is_unused)
-{
-#define FAIL(fmt, args...) do { \
- PRINT_G(KERN_ERR, fmt , ## args); \
- remove_card(dev); \
- return error; \
- } while (0)
-
- char irq_buf[16];
- struct hpsb_host *host;
- struct ti_lynx *lynx; /* shortcut to currently handled device */
- struct ti_pcl pcl;
- u32 *pcli;
- int i;
- int error;
-
- error = -ENXIO;
-
- if (pci_set_dma_mask(dev, DMA_BIT_MASK(32)))
- FAIL("DMA address limits not supported for PCILynx hardware");
- if (pci_enable_device(dev))
- FAIL("failed to enable PCILynx hardware");
- pci_set_master(dev);
-
- error = -ENOMEM;
-
- host = hpsb_alloc_host(&lynx_driver, sizeof(struct ti_lynx), &dev->dev);
- if (!host) FAIL("failed to allocate control structure memory");
-
- lynx = host->hostdata;
- lynx->id = card_id++;
- lynx->dev = dev;
- lynx->state = clear;
- lynx->host = host;
- host->pdev = dev;
- pci_set_drvdata(dev, lynx);
-
- spin_lock_init(&lynx->lock);
- spin_lock_init(&lynx->phy_reg_lock);
-
- lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE,
- &lynx->pcl_mem_dma);
-
- if (lynx->pcl_mem != NULL) {
- lynx->state = have_pcl_mem;
- PRINT(KERN_INFO, lynx->id,
- "allocated PCL memory %d Bytes @ 0x%p", LOCALRAM_SIZE,
- lynx->pcl_mem);
- } else {
- FAIL("failed to allocate PCL memory area");
- }
-
- lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE,
- &lynx->rcv_page_dma);
- if (lynx->rcv_page == NULL) {
- FAIL("failed to allocate receive buffer");
- }
- lynx->state = have_1394_buffers;
-
- for (i = 0; i < ISORCV_PAGES; i++) {
- lynx->iso_rcv.page[i] =
- pci_alloc_consistent(dev, PAGE_SIZE,
- &lynx->iso_rcv.page_dma[i]);
- if (lynx->iso_rcv.page[i] == NULL) {
- FAIL("failed to allocate iso receive buffers");
- }
- }
-
- lynx->registers = ioremap_nocache(pci_resource_start(dev,0),
- PCILYNX_MAX_REGISTER);
- lynx->local_ram = ioremap(pci_resource_start(dev,1), PCILYNX_MAX_MEMORY);
- lynx->aux_port = ioremap(pci_resource_start(dev,2), PCILYNX_MAX_MEMORY);
- lynx->local_rom = ioremap(pci_resource_start(dev,PCI_ROM_RESOURCE),
- PCILYNX_MAX_MEMORY);
- lynx->state = have_iomappings;
-
- if (lynx->registers == NULL) {
- FAIL("failed to remap registers - card not accessible");
- }
-
- reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
- /* Fix buggy cards with autoboot pin not tied low: */
- reg_write(lynx, DMA0_CHAN_CTRL, 0);
-
- sprintf (irq_buf, "%d", dev->irq);
-
- if (!request_irq(dev->irq, lynx_irq_handler, IRQF_SHARED,
- PCILYNX_DRIVER_NAME, lynx)) {
- PRINT(KERN_INFO, lynx->id, "allocated interrupt %s", irq_buf);
- lynx->state = have_intr;
- } else {
- FAIL("failed to allocate shared interrupt %s", irq_buf);
- }
-
- /* alloc_pcl return values are not checked, it is expected that the
- * provided PCL space is sufficient for the initial allocations */
- lynx->rcv_pcl = alloc_pcl(lynx);
- lynx->rcv_pcl_start = alloc_pcl(lynx);
- lynx->async.pcl = alloc_pcl(lynx);
- lynx->async.pcl_start = alloc_pcl(lynx);
- lynx->iso_send.pcl = alloc_pcl(lynx);
- lynx->iso_send.pcl_start = alloc_pcl(lynx);
-
- for (i = 0; i < NUM_ISORCV_PCL; i++) {
- lynx->iso_rcv.pcl[i] = alloc_pcl(lynx);
- }
- lynx->iso_rcv.pcl_start = alloc_pcl(lynx);
-
- /* all allocations successful - simple init stuff follows */
-
- reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);
-
- tasklet_init(&lynx->iso_rcv.tq, (void (*)(unsigned long))iso_rcv_bh,
- (unsigned long)lynx);
-
- spin_lock_init(&lynx->iso_rcv.lock);
-
- spin_lock_init(&lynx->async.queue_lock);
- lynx->async.channel = CHANNEL_ASYNC_SEND;
- spin_lock_init(&lynx->iso_send.queue_lock);
- lynx->iso_send.channel = CHANNEL_ISO_SEND;
-
- PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, "
- "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom,
- lynx->local_ram, lynx->aux_port);
-
- /* now, looking for PHY register set */
- if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) {
- lynx->phyic.reg_1394a = 1;
- PRINT(KERN_INFO, lynx->id,
- "found 1394a conform PHY (using extended register set)");
- lynx->phyic.vendor = get_phy_vendorid(lynx);
- lynx->phyic.product = get_phy_productid(lynx);
- } else {
- lynx->phyic.reg_1394a = 0;
- PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
- }
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
-
- INIT_LIST_HEAD(&lynx->async.queue);
- INIT_LIST_HEAD(&lynx->async.pcl_queue);
- INIT_LIST_HEAD(&lynx->iso_send.queue);
- INIT_LIST_HEAD(&lynx->iso_send.pcl_queue);
-
- pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
- put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
-
- pcl.next = PCL_NEXT_INVALID;
- pcl.async_error_next = PCL_NEXT_INVALID;
-
- pcl.buffer[0].control = PCL_CMD_RCV | 16;
-#ifndef __BIG_ENDIAN
- pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
- pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-
- pcl.buffer[0].pointer = lynx->rcv_page_dma;
- pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
- put_pcl(lynx, lynx->rcv_pcl, &pcl);
-
- pcl.next = pcl_bus(lynx, lynx->async.pcl);
- pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
- put_pcl(lynx, lynx->async.pcl_start, &pcl);
-
- pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
- pcl.async_error_next = PCL_NEXT_INVALID;
- put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
-
- pcl.next = PCL_NEXT_INVALID;
- pcl.async_error_next = PCL_NEXT_INVALID;
- pcl.buffer[0].control = PCL_CMD_RCV | 4;
-#ifndef __BIG_ENDIAN
- pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
- pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
-
- for (i = 0; i < NUM_ISORCV_PCL; i++) {
- int page = i / ISORCV_PER_PAGE;
- int sec = i % ISORCV_PER_PAGE;
-
- pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page]
- + sec * MAX_ISORCV_SIZE;
- pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
- put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
- }
-
- pcli = (u32 *)&pcl;
- for (i = 0; i < NUM_ISORCV_PCL; i++) {
- pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
- }
- put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
-
- /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
- reg_write(lynx, FIFO_SIZES, 0x003030a0);
- /* 20 byte threshold before triggering PCI transfer */
- reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
- /* threshold on both send FIFOs before transmitting:
- FIFO size - cache line size - 1 */
- i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
- i = 0x30 - i - 1;
- reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
-
- reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
-
- reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
- | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET
- | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK
- | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC
- | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW
- | LINK_INT_ATF_UNDERFLOW);
-
- reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
- reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
- reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
- DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
- | DMA_WORD1_CMP_MATCH_EXACT | DMA_WORD1_CMP_MATCH_BUS_BCAST
- | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
-
- run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
-
- reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
- reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
- reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
-
- run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
-
- reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
- | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN
- | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
- | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX);
-
- if (!lynx->phyic.reg_1394a) {
- if (!hpsb_disable_irm) {
- /* attempt to enable contender bit -FIXME- would this
- * work elsewhere? */
- reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
- reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
- }
- } else {
- /* set the contender (if appropriate) and LCtrl bit in the
- * extended PHY register set. (Should check that PHY_02_EXTENDED
- * is set in register 2?)
- */
- i = get_phy_reg(lynx, 4);
- i |= PHY_04_LCTRL;
- if (hpsb_disable_irm)
- i &= ~PHY_04_CONTENDER;
- else
- i |= PHY_04_CONTENDER;
- if (i != -1) set_phy_reg(lynx, 4, i);
- }
-
- if (!skip_eeprom)
- {
- /* needed for i2c communication with serial eeprom */
- struct i2c_adapter *i2c_ad;
- struct i2c_algo_bit_data i2c_adapter_data;
-
- error = -ENOMEM;
- i2c_ad = kzalloc(sizeof(*i2c_ad), GFP_KERNEL);
- if (!i2c_ad) FAIL("failed to allocate I2C adapter memory");
-
- strlcpy(i2c_ad->name, "PCILynx I2C", sizeof(i2c_ad->name));
- i2c_adapter_data = bit_data;
- i2c_ad->algo_data = &i2c_adapter_data;
- i2c_adapter_data.data = lynx;
- i2c_ad->dev.parent = &dev->dev;
-
- PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d",
- reg_read(lynx, SERIAL_EEPROM_CONTROL));
-
- /* reset hardware to sane state */
- lynx->i2c_driven_state = 0x00000070;
- reg_write(lynx, SERIAL_EEPROM_CONTROL, lynx->i2c_driven_state);
-
- if (i2c_bit_add_bus(i2c_ad) < 0)
- {
- kfree(i2c_ad);
- error = -ENXIO;
- FAIL("unable to register i2c");
- }
- else
- {
- /* do i2c stuff */
- unsigned char i2c_cmd = 0x10;
- struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd },
- { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->bus_info_block }
- };
-
- /* we use i2c_transfer because we have no i2c_client
- at hand */
- if (i2c_transfer(i2c_ad, msg, 2) < 0) {
- PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c");
- } else {
- PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom");
- /* FIXME: probably we should rewrite the max_rec, max_ROM(1394a),
- * generation(1394a) and link_spd(1394a) field and recalculate
- * the CRC */
-
- for (i = 0; i < 5 ; i++)
- PRINTD(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",
- i, be32_to_cpu(lynx->bus_info_block[i]));
-
- /* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */
- if (((be32_to_cpu(lynx->bus_info_block[0]) & 0xffff0000) == 0x04040000) &&
- (lynx->bus_info_block[1] == IEEE1394_BUSID_MAGIC))
- {
- PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");
- } else {
- kfree(i2c_ad);
- error = -ENXIO;
- FAIL("read something from serial eeprom, but it does not seem to be a valid bus info block");
- }
-
- }
-
- i2c_del_adapter(i2c_ad);
- kfree(i2c_ad);
- }
- }
-
- host->csr.guid_hi = be32_to_cpu(lynx->bus_info_block[3]);
- host->csr.guid_lo = be32_to_cpu(lynx->bus_info_block[4]);
- host->csr.cyc_clk_acc = (be32_to_cpu(lynx->bus_info_block[2]) >> 16) & 0xff;
- host->csr.max_rec = (be32_to_cpu(lynx->bus_info_block[2]) >> 12) & 0xf;
- if (!lynx->phyic.reg_1394a)
- host->csr.lnk_spd = (get_phy_reg(lynx, 2) & 0xc0) >> 6;
- else
- host->csr.lnk_spd = be32_to_cpu(lynx->bus_info_block[2]) & 0x7;
-
- if (hpsb_add_host(host)) {
- error = -ENOMEM;
- FAIL("Failed to register host with highlevel");
- }
-
- lynx->state = is_host;
-
- return 0;
-#undef FAIL
-}
-
-
-static struct pci_device_id pci_table[] = {
- {
- .vendor = PCI_VENDOR_ID_TI,
- .device = PCI_DEVICE_ID_TI_PCILYNX,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { } /* Terminating entry */
-};
-
-static struct pci_driver lynx_pci_driver = {
- .name = PCILYNX_DRIVER_NAME,
- .id_table = pci_table,
- .probe = add_card,
- .remove = remove_card,
-};
-
-static struct hpsb_host_driver lynx_driver = {
- .owner = THIS_MODULE,
- .name = PCILYNX_DRIVER_NAME,
- .set_hw_config_rom = NULL,
- .transmit_packet = lynx_transmit,
- .devctl = lynx_devctl,
- .isoctl = NULL,
-};
-
-MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");
-MODULE_DESCRIPTION("driver for Texas Instruments PCI Lynx IEEE-1394 controller");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("pcilynx");
-MODULE_DEVICE_TABLE(pci, pci_table);
-
-static int __init pcilynx_init(void)
-{
- int ret;
-
- ret = pci_register_driver(&lynx_pci_driver);
- if (ret < 0) {
- PRINT_G(KERN_ERR, "PCI module init failed");
- return ret;
- }
-
- return 0;
-}
-
-static void __exit pcilynx_cleanup(void)
-{
- pci_unregister_driver(&lynx_pci_driver);
-}
-
-
-module_init(pcilynx_init);
-module_exit(pcilynx_cleanup);
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
deleted file mode 100644
index 693a169acea3..000000000000
--- a/drivers/ieee1394/pcilynx.h
+++ /dev/null
@@ -1,468 +0,0 @@
-#ifndef __PCILYNX_H__
-#define __PCILYNX_H__
-
-
-#define PCILYNX_DRIVER_NAME "pcilynx"
-#define PCILYNX_MAJOR 177
-
-#define PCILYNX_MINOR_AUX_START 0
-#define PCILYNX_MINOR_ROM_START 16
-#define PCILYNX_MINOR_RAM_START 32
-
-#define PCILYNX_MAX_REGISTER 0xfff
-#define PCILYNX_MAX_MEMORY 0xffff
-
-#define PCI_DEVICE_ID_TI_PCILYNX 0x8000
-#define MAX_PCILYNX_CARDS 4
-#define LOCALRAM_SIZE 4096
-
-#define NUM_ISORCV_PCL 4
-#define MAX_ISORCV_SIZE 2048
-#define ISORCV_PER_PAGE (PAGE_SIZE / MAX_ISORCV_SIZE)
-#define ISORCV_PAGES (NUM_ISORCV_PCL / ISORCV_PER_PAGE)
-
-#define CHANNEL_LOCALBUS 0
-#define CHANNEL_ASYNC_RCV 1
-#define CHANNEL_ISO_RCV 2
-#define CHANNEL_ASYNC_SEND 3
-#define CHANNEL_ISO_SEND 4
-
-#define PCILYNX_CONFIG_ROM_LENGTH 1024
-
-typedef int pcl_t;
-
-struct ti_lynx {
- int id; /* sequential card number */
-
- spinlock_t lock;
-
- struct pci_dev *dev;
-
- struct {
- unsigned reg_1394a:1;
- u32 vendor;
- u32 product;
- } phyic;
-
- enum { clear, have_intr, have_aux_buf, have_pcl_mem,
- have_1394_buffers, have_iomappings, is_host } state;
-
- /* remapped memory spaces */
- void __iomem *registers;
- void __iomem *local_rom;
- void __iomem *local_ram;
- void __iomem *aux_port;
- __be32 bus_info_block[5];
-
- /*
- * use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for
- * LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes);
- * the following is an allocation bitmap
- */
- u8 pcl_bmap[LOCALRAM_SIZE / 1024];
-
- /* point to PCLs memory area if needed */
- void *pcl_mem;
- dma_addr_t pcl_mem_dma;
-
- /* PCLs for local mem / aux transfers */
- pcl_t dmem_pcl;
-
- /* IEEE-1394 part follows */
- struct hpsb_host *host;
-
- int phyid, isroot;
- int selfid_size;
- int phy_reg0;
-
- spinlock_t phy_reg_lock;
-
- pcl_t rcv_pcl_start, rcv_pcl;
- void *rcv_page;
- dma_addr_t rcv_page_dma;
- int rcv_active;
-
- struct lynx_send_data {
- pcl_t pcl_start, pcl;
- struct list_head queue;
- struct list_head pcl_queue; /* this queue contains at most one packet */
- spinlock_t queue_lock;
- dma_addr_t header_dma, data_dma;
- int channel;
- } async, iso_send;
-
- struct {
- pcl_t pcl[NUM_ISORCV_PCL];
- u32 stat[NUM_ISORCV_PCL];
- void *page[ISORCV_PAGES];
- dma_addr_t page_dma[ISORCV_PAGES];
- pcl_t pcl_start;
- int chan_count;
- int next, last, used, running;
- struct tasklet_struct tq;
- spinlock_t lock;
- } iso_rcv;
-
- u32 i2c_driven_state; /* the state we currently drive the Serial EEPROM Control register */
-};
-
-/* the per-file data structure for mem space access */
-struct memdata {
- struct ti_lynx *lynx;
- int cid;
- atomic_t aux_intr_last_seen;
- /* enum values are the same as LBUS_ADDR_SEL_* values below */
- enum { rom = 0x10000, aux = 0x20000, ram = 0 } type;
-};
-
-
-
-/*
- * Register read and write helper functions.
- */
-static inline void reg_write(const struct ti_lynx *lynx, int offset, u32 data)
-{
- writel(data, lynx->registers + offset);
-}
-
-static inline u32 reg_read(const struct ti_lynx *lynx, int offset)
-{
- return readl(lynx->registers + offset);
-}
-
-static inline void reg_set_bits(const struct ti_lynx *lynx, int offset,
- u32 mask)
-{
- reg_write(lynx, offset, (reg_read(lynx, offset) | mask));
-}
-
-static inline void reg_clear_bits(const struct ti_lynx *lynx, int offset,
- u32 mask)
-{
- reg_write(lynx, offset, (reg_read(lynx, offset) & ~mask));
-}
-
-
-
-/* chip register definitions follow */
-
-#define PCI_LATENCY_CACHELINE 0x0c
-
-#define MISC_CONTROL 0x40
-#define MISC_CONTROL_SWRESET (1<<0)
-
-#define SERIAL_EEPROM_CONTROL 0x44
-
-#define PCI_INT_STATUS 0x48
-#define PCI_INT_ENABLE 0x4c
-/* status and enable have identical bit numbers */
-#define PCI_INT_INT_PEND (1<<31)
-#define PCI_INT_FORCED_INT (1<<30)
-#define PCI_INT_SLV_ADR_PERR (1<<28)
-#define PCI_INT_SLV_DAT_PERR (1<<27)
-#define PCI_INT_MST_DAT_PERR (1<<26)
-#define PCI_INT_MST_DEV_TIMEOUT (1<<25)
-#define PCI_INT_INTERNAL_SLV_TIMEOUT (1<<23)
-#define PCI_INT_AUX_TIMEOUT (1<<18)
-#define PCI_INT_AUX_INT (1<<17)
-#define PCI_INT_1394 (1<<16)
-#define PCI_INT_DMA4_PCL (1<<9)
-#define PCI_INT_DMA4_HLT (1<<8)
-#define PCI_INT_DMA3_PCL (1<<7)
-#define PCI_INT_DMA3_HLT (1<<6)
-#define PCI_INT_DMA2_PCL (1<<5)
-#define PCI_INT_DMA2_HLT (1<<4)
-#define PCI_INT_DMA1_PCL (1<<3)
-#define PCI_INT_DMA1_HLT (1<<2)
-#define PCI_INT_DMA0_PCL (1<<1)
-#define PCI_INT_DMA0_HLT (1<<0)
-/* all DMA interrupts combined: */
-#define PCI_INT_DMA_ALL 0x3ff
-
-#define PCI_INT_DMA_HLT(chan) (1 << (chan * 2))
-#define PCI_INT_DMA_PCL(chan) (1 << (chan * 2 + 1))
-
-#define LBUS_ADDR 0xb4
-#define LBUS_ADDR_SEL_RAM (0x0<<16)
-#define LBUS_ADDR_SEL_ROM (0x1<<16)
-#define LBUS_ADDR_SEL_AUX (0x2<<16)
-#define LBUS_ADDR_SEL_ZV (0x3<<16)
-
-#define GPIO_CTRL_A 0xb8
-#define GPIO_CTRL_B 0xbc
-#define GPIO_DATA_BASE 0xc0
-
-#define DMA_BREG(base, chan) (base + chan * 0x20)
-#define DMA_SREG(base, chan) (base + chan * 0x10)
-
-#define DMA0_PREV_PCL 0x100
-#define DMA1_PREV_PCL 0x120
-#define DMA2_PREV_PCL 0x140
-#define DMA3_PREV_PCL 0x160
-#define DMA4_PREV_PCL 0x180
-#define DMA_PREV_PCL(chan) (DMA_BREG(DMA0_PREV_PCL, chan))
-
-#define DMA0_CURRENT_PCL 0x104
-#define DMA1_CURRENT_PCL 0x124
-#define DMA2_CURRENT_PCL 0x144
-#define DMA3_CURRENT_PCL 0x164
-#define DMA4_CURRENT_PCL 0x184
-#define DMA_CURRENT_PCL(chan) (DMA_BREG(DMA0_CURRENT_PCL, chan))
-
-#define DMA0_CHAN_STAT 0x10c
-#define DMA1_CHAN_STAT 0x12c
-#define DMA2_CHAN_STAT 0x14c
-#define DMA3_CHAN_STAT 0x16c
-#define DMA4_CHAN_STAT 0x18c
-#define DMA_CHAN_STAT(chan) (DMA_BREG(DMA0_CHAN_STAT, chan))
-/* CHAN_STATUS registers share bits */
-#define DMA_CHAN_STAT_SELFID (1<<31)
-#define DMA_CHAN_STAT_ISOPKT (1<<30)
-#define DMA_CHAN_STAT_PCIERR (1<<29)
-#define DMA_CHAN_STAT_PKTERR (1<<28)
-#define DMA_CHAN_STAT_PKTCMPL (1<<27)
-#define DMA_CHAN_STAT_SPECIALACK (1<<14)
-
-
-#define DMA0_CHAN_CTRL 0x110
-#define DMA1_CHAN_CTRL 0x130
-#define DMA2_CHAN_CTRL 0x150
-#define DMA3_CHAN_CTRL 0x170
-#define DMA4_CHAN_CTRL 0x190
-#define DMA_CHAN_CTRL(chan) (DMA_BREG(DMA0_CHAN_CTRL, chan))
-/* CHAN_CTRL registers share bits */
-#define DMA_CHAN_CTRL_ENABLE (1<<31)
-#define DMA_CHAN_CTRL_BUSY (1<<30)
-#define DMA_CHAN_CTRL_LINK (1<<29)
-
-#define DMA0_READY 0x114
-#define DMA1_READY 0x134
-#define DMA2_READY 0x154
-#define DMA3_READY 0x174
-#define DMA4_READY 0x194
-#define DMA_READY(chan) (DMA_BREG(DMA0_READY, chan))
-
-#define DMA_GLOBAL_REGISTER 0x908
-
-#define FIFO_SIZES 0xa00
-
-#define FIFO_CONTROL 0xa10
-#define FIFO_CONTROL_GRF_FLUSH (1<<4)
-#define FIFO_CONTROL_ITF_FLUSH (1<<3)
-#define FIFO_CONTROL_ATF_FLUSH (1<<2)
-
-#define FIFO_XMIT_THRESHOLD 0xa14
-
-#define DMA0_WORD0_CMP_VALUE 0xb00
-#define DMA1_WORD0_CMP_VALUE 0xb10
-#define DMA2_WORD0_CMP_VALUE 0xb20
-#define DMA3_WORD0_CMP_VALUE 0xb30
-#define DMA4_WORD0_CMP_VALUE 0xb40
-#define DMA_WORD0_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan))
-
-#define DMA0_WORD0_CMP_ENABLE 0xb04
-#define DMA1_WORD0_CMP_ENABLE 0xb14
-#define DMA2_WORD0_CMP_ENABLE 0xb24
-#define DMA3_WORD0_CMP_ENABLE 0xb34
-#define DMA4_WORD0_CMP_ENABLE 0xb44
-#define DMA_WORD0_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD0_CMP_ENABLE,chan))
-
-#define DMA0_WORD1_CMP_VALUE 0xb08
-#define DMA1_WORD1_CMP_VALUE 0xb18
-#define DMA2_WORD1_CMP_VALUE 0xb28
-#define DMA3_WORD1_CMP_VALUE 0xb38
-#define DMA4_WORD1_CMP_VALUE 0xb48
-#define DMA_WORD1_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan))
-
-#define DMA0_WORD1_CMP_ENABLE 0xb0c
-#define DMA1_WORD1_CMP_ENABLE 0xb1c
-#define DMA2_WORD1_CMP_ENABLE 0xb2c
-#define DMA3_WORD1_CMP_ENABLE 0xb3c
-#define DMA4_WORD1_CMP_ENABLE 0xb4c
-#define DMA_WORD1_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD1_CMP_ENABLE,chan))
-/* word 1 compare enable flags */
-#define DMA_WORD1_CMP_MATCH_OTHERBUS (1<<15)
-#define DMA_WORD1_CMP_MATCH_BROADCAST (1<<14)
-#define DMA_WORD1_CMP_MATCH_BUS_BCAST (1<<13)
-#define DMA_WORD1_CMP_MATCH_LOCAL_NODE (1<<12)
-#define DMA_WORD1_CMP_MATCH_EXACT (1<<11)
-#define DMA_WORD1_CMP_ENABLE_SELF_ID (1<<10)
-#define DMA_WORD1_CMP_ENABLE_MASTER (1<<8)
-
-#define LINK_ID 0xf00
-#define LINK_ID_BUS(id) (id<<22)
-#define LINK_ID_NODE(id) (id<<16)
-
-#define LINK_CONTROL 0xf04
-#define LINK_CONTROL_BUSY (1<<29)
-#define LINK_CONTROL_TX_ISO_EN (1<<26)
-#define LINK_CONTROL_RX_ISO_EN (1<<25)
-#define LINK_CONTROL_TX_ASYNC_EN (1<<24)
-#define LINK_CONTROL_RX_ASYNC_EN (1<<23)
-#define LINK_CONTROL_RESET_TX (1<<21)
-#define LINK_CONTROL_RESET_RX (1<<20)
-#define LINK_CONTROL_CYCMASTER (1<<11)
-#define LINK_CONTROL_CYCSOURCE (1<<10)
-#define LINK_CONTROL_CYCTIMEREN (1<<9)
-#define LINK_CONTROL_RCV_CMP_VALID (1<<7)
-#define LINK_CONTROL_SNOOP_ENABLE (1<<6)
-
-#define CYCLE_TIMER 0xf08
-
-#define LINK_PHY 0xf0c
-#define LINK_PHY_READ (1<<31)
-#define LINK_PHY_WRITE (1<<30)
-#define LINK_PHY_ADDR(addr) (addr<<24)
-#define LINK_PHY_WDATA(data) (data<<16)
-#define LINK_PHY_RADDR(addr) (addr<<8)
-
-
-#define LINK_INT_STATUS 0xf14
-#define LINK_INT_ENABLE 0xf18
-/* status and enable have identical bit numbers */
-#define LINK_INT_LINK_INT (1<<31)
-#define LINK_INT_PHY_TIMEOUT (1<<30)
-#define LINK_INT_PHY_REG_RCVD (1<<29)
-#define LINK_INT_PHY_BUSRESET (1<<28)
-#define LINK_INT_TX_RDY (1<<26)
-#define LINK_INT_RX_DATA_RDY (1<<25)
-#define LINK_INT_ISO_STUCK (1<<20)
-#define LINK_INT_ASYNC_STUCK (1<<19)
-#define LINK_INT_SENT_REJECT (1<<17)
-#define LINK_INT_HDR_ERR (1<<16)
-#define LINK_INT_TX_INVALID_TC (1<<15)
-#define LINK_INT_CYC_SECOND (1<<11)
-#define LINK_INT_CYC_START (1<<10)
-#define LINK_INT_CYC_DONE (1<<9)
-#define LINK_INT_CYC_PENDING (1<<8)
-#define LINK_INT_CYC_LOST (1<<7)
-#define LINK_INT_CYC_ARB_FAILED (1<<6)
-#define LINK_INT_GRF_OVERFLOW (1<<5)
-#define LINK_INT_ITF_UNDERFLOW (1<<4)
-#define LINK_INT_ATF_UNDERFLOW (1<<3)
-#define LINK_INT_ISOARB_FAILED (1<<0)
-
-/* PHY specifics */
-#define PHY_VENDORID_TI 0x800028
-#define PHY_PRODUCTID_TSB41LV03 0x000000
-
-
-/* this is the physical layout of a PCL, its size is 128 bytes */
-struct ti_pcl {
- u32 next;
- u32 async_error_next;
- u32 user_data;
- u32 pcl_status;
- u32 remaining_transfer_count;
- u32 next_data_buffer;
- struct {
- u32 control;
- u32 pointer;
- } buffer[13] __attribute__ ((packed));
-} __attribute__ ((packed));
-
-#include <linux/stddef.h>
-#define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
-
-
-static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- const struct ti_pcl *pcl)
-{
- memcpy_le32((u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
- (u32 *)pcl, sizeof(struct ti_pcl));
-}
-
-static inline void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- struct ti_pcl *pcl)
-{
- memcpy_le32((u32 *)pcl,
- (u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
- sizeof(struct ti_pcl));
-}
-
-static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
-{
- return lynx->pcl_mem_dma + pclid * sizeof(struct ti_pcl);
-}
-
-
-#if defined (__BIG_ENDIAN)
-typedef struct ti_pcl pcltmp_t;
-
-static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- pcltmp_t *tmp)
-{
- get_pcl(lynx, pclid, tmp);
- return tmp;
-}
-
-static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- pcltmp_t *tmp)
-{
- put_pcl(lynx, pclid, tmp);
-}
-
-#else
-typedef int pcltmp_t; /* just a dummy */
-
-static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- pcltmp_t *tmp)
-{
- return lynx->pcl_mem + pclid * sizeof(struct ti_pcl);
-}
-
-static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- pcltmp_t *tmp)
-{
-}
-#endif
-
-
-static inline void run_sub_pcl(const struct ti_lynx *lynx, pcl_t pclid, int idx,
- int dmachan)
-{
- reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20,
- pcl_bus(lynx, pclid) + idx * 4);
- reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20,
- DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK);
-}
-
-static inline void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan)
-{
- run_sub_pcl(lynx, pclid, 0, dmachan);
-}
-
-#define PCL_NEXT_INVALID (1<<0)
-
-/* transfer commands */
-#define PCL_CMD_RCV (0x1<<24)
-#define PCL_CMD_RCV_AND_UPDATE (0xa<<24)
-#define PCL_CMD_XMT (0x2<<24)
-#define PCL_CMD_UNFXMT (0xc<<24)
-#define PCL_CMD_PCI_TO_LBUS (0x8<<24)
-#define PCL_CMD_LBUS_TO_PCI (0x9<<24)
-
-/* aux commands */
-#define PCL_CMD_NOP (0x0<<24)
-#define PCL_CMD_LOAD (0x3<<24)
-#define PCL_CMD_STOREQ (0x4<<24)
-#define PCL_CMD_STORED (0xb<<24)
-#define PCL_CMD_STORE0 (0x5<<24)
-#define PCL_CMD_STORE1 (0x6<<24)
-#define PCL_CMD_COMPARE (0xe<<24)
-#define PCL_CMD_SWAP_COMPARE (0xf<<24)
-#define PCL_CMD_ADD (0xd<<24)
-#define PCL_CMD_BRANCH (0x7<<24)
-
-/* BRANCH condition codes */
-#define PCL_COND_DMARDY_SET (0x1<<20)
-#define PCL_COND_DMARDY_CLEAR (0x2<<20)
-
-#define PCL_GEN_INTR (1<<19)
-#define PCL_LAST_BUFF (1<<18)
-#define PCL_LAST_CMD (PCL_LAST_BUFF)
-#define PCL_WAITSTAT (1<<17)
-#define PCL_BIGENDIAN (1<<16)
-#define PCL_ISOMODE (1<<12)
-
-#endif
diff --git a/drivers/ieee1394/raw1394-private.h b/drivers/ieee1394/raw1394-private.h
deleted file mode 100644
index 7a225a405987..000000000000
--- a/drivers/ieee1394/raw1394-private.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef IEEE1394_RAW1394_PRIVATE_H
-#define IEEE1394_RAW1394_PRIVATE_H
-
-/* header for definitions that are private to the raw1394 driver
- and not visible to user-space */
-
-#define RAW1394_DEVICE_MAJOR 171
-#define RAW1394_DEVICE_NAME "raw1394"
-
-#define RAW1394_MAX_USER_CSR_DIRS 16
-
-struct iso_block_store {
- atomic_t refcount;
- size_t data_size;
- quadlet_t data[0];
-};
-
-enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0,
- RAW1394_ISO_RECV = 1,
- RAW1394_ISO_XMIT = 2 };
-
-struct file_info {
- struct list_head list;
-
- struct mutex state_mutex;
- enum { opened, initialized, connected } state;
- unsigned int protocol_version;
-
- struct hpsb_host *host;
-
- struct list_head req_pending; /* protected by reqlists_lock */
- struct list_head req_complete; /* protected by reqlists_lock */
- spinlock_t reqlists_lock;
- wait_queue_head_t wait_complete;
-
- struct list_head addr_list; /* protected by host_info_lock */
-
- u8 __user *fcp_buffer;
-
- u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
-
- /* new rawiso API */
- enum raw1394_iso_state iso_state;
- struct hpsb_iso *iso_handle;
-
- /* User space's CSR1212 dynamic ConfigROM directories */
- struct csr1212_keyval *csr1212_dirs[RAW1394_MAX_USER_CSR_DIRS];
-
- /* Legacy ConfigROM update flag */
- u8 cfgrom_upd;
-};
-
-struct arm_addr {
- struct list_head addr_list; /* file_info list */
- u64 start, end;
- u64 arm_tag;
- u8 access_rights;
- u8 notification_options;
- u8 client_transactions;
- u64 recvb;
- u16 rec_length;
- u8 *addr_space_buffer; /* accessed by read/write/lock requests */
-};
-
-struct pending_request {
- struct list_head list;
- struct file_info *file_info;
- struct hpsb_packet *packet;
- struct iso_block_store *ibs;
- quadlet_t *data;
- int free_data;
- struct raw1394_request req;
-};
-
-struct host_info {
- struct list_head list;
- struct hpsb_host *host;
- struct list_head file_info_list; /* protected by host_info_lock */
-};
-
-#endif /* IEEE1394_RAW1394_PRIVATE_H */
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
deleted file mode 100644
index f3401427404c..000000000000
--- a/drivers/ieee1394/raw1394.c
+++ /dev/null
@@ -1,3096 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Raw interface to the bus
- *
- * Copyright (C) 1999, 2000 Andreas E. Bombe
- * 2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- * 2002 Christian Toegel <christian.toegel@gmx.at>
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * configuration ROM manipulation
- * address range mapping
- * adaptation for new (transparent) loopback mechanism
- * sending of arbitrary async packets
- * Christian Toegel <christian.toegel@gmx.at>
- * address range mapping
- * lock64 request
- * transmit physical packet
- * busreset notification control (switch on/off)
- * busreset with selection of type (short/long)
- * request_reply
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/cdev.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
-#include <linux/compat.h>
-
-#include "csr1212.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "iso.h"
-#include "nodemgr.h"
-#include "raw1394.h"
-#include "raw1394-private.h"
-
-#define int2ptr(x) ((void __user *)(unsigned long)x)
-#define ptr2int(x) ((u64)(unsigned long)(void __user *)x)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define RAW1394_DEBUG
-#endif
-
-#ifdef RAW1394_DEBUG
-#define DBGMSG(fmt, args...) \
-printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
-#else
-#define DBGMSG(fmt, args...) do {} while (0)
-#endif
-
-static LIST_HEAD(host_info_list);
-static int host_count;
-static DEFINE_SPINLOCK(host_info_lock);
-static atomic_t internal_generation = ATOMIC_INIT(0);
-
-static atomic_t iso_buffer_size;
-static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */
-
-static struct hpsb_highlevel raw1394_highlevel;
-
-static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
- u64 addr, size_t length, u16 flags);
-static int arm_write(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t * data, u64 addr, size_t length, u16 flags);
-static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
- u16 flags);
-static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
- u16 flags);
-static const struct hpsb_address_ops arm_ops = {
- .read = arm_read,
- .write = arm_write,
- .lock = arm_lock,
- .lock64 = arm_lock64,
-};
-
-static void queue_complete_cb(struct pending_request *req);
-
-static struct pending_request *__alloc_pending_request(gfp_t flags)
-{
- struct pending_request *req;
-
- req = kzalloc(sizeof(*req), flags);
- if (req)
- INIT_LIST_HEAD(&req->list);
-
- return req;
-}
-
-static inline struct pending_request *alloc_pending_request(void)
-{
- return __alloc_pending_request(GFP_KERNEL);
-}
-
-static void free_pending_request(struct pending_request *req)
-{
- if (req->ibs) {
- if (atomic_dec_and_test(&req->ibs->refcount)) {
- atomic_sub(req->ibs->data_size, &iso_buffer_size);
- kfree(req->ibs);
- }
- } else if (req->free_data) {
- kfree(req->data);
- }
- hpsb_free_packet(req->packet);
- kfree(req);
-}
-
-/* fi->reqlists_lock must be taken */
-static void __queue_complete_req(struct pending_request *req)
-{
- struct file_info *fi = req->file_info;
-
- list_move_tail(&req->list, &fi->req_complete);
- wake_up(&fi->wait_complete);
-}
-
-static void queue_complete_req(struct pending_request *req)
-{
- unsigned long flags;
- struct file_info *fi = req->file_info;
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- __queue_complete_req(req);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-}
-
-static void queue_complete_cb(struct pending_request *req)
-{
- struct hpsb_packet *packet = req->packet;
- int rcode = (packet->header[1] >> 12) & 0xf;
-
- switch (packet->ack_code) {
- case ACKX_NONE:
- case ACKX_SEND_ERROR:
- req->req.error = RAW1394_ERROR_SEND_ERROR;
- break;
- case ACKX_ABORTED:
- req->req.error = RAW1394_ERROR_ABORTED;
- break;
- case ACKX_TIMEOUT:
- req->req.error = RAW1394_ERROR_TIMEOUT;
- break;
- default:
- req->req.error = (packet->ack_code << 16) | rcode;
- break;
- }
-
- if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) {
- req->req.length = 0;
- }
-
- if ((req->req.type == RAW1394_REQ_ASYNC_READ) ||
- (req->req.type == RAW1394_REQ_ASYNC_WRITE) ||
- (req->req.type == RAW1394_REQ_ASYNC_STREAM) ||
- (req->req.type == RAW1394_REQ_LOCK) ||
- (req->req.type == RAW1394_REQ_LOCK64))
- hpsb_free_tlabel(packet);
-
- queue_complete_req(req);
-}
-
-static void add_host(struct hpsb_host *host)
-{
- struct host_info *hi;
- unsigned long flags;
-
- hi = kmalloc(sizeof(*hi), GFP_KERNEL);
-
- if (hi) {
- INIT_LIST_HEAD(&hi->list);
- hi->host = host;
- INIT_LIST_HEAD(&hi->file_info_list);
-
- spin_lock_irqsave(&host_info_lock, flags);
- list_add_tail(&hi->list, &host_info_list);
- host_count++;
- spin_unlock_irqrestore(&host_info_lock, flags);
- }
-
- atomic_inc(&internal_generation);
-}
-
-static struct host_info *find_host_info(struct hpsb_host *host)
-{
- struct host_info *hi;
-
- list_for_each_entry(hi, &host_info_list, list)
- if (hi->host == host)
- return hi;
-
- return NULL;
-}
-
-static void remove_host(struct hpsb_host *host)
-{
- struct host_info *hi;
- unsigned long flags;
-
- spin_lock_irqsave(&host_info_lock, flags);
- hi = find_host_info(host);
-
- if (hi != NULL) {
- list_del(&hi->list);
- host_count--;
- /*
- FIXME: address ranges should be removed
- and fileinfo states should be initialized
- (including setting generation to
- internal-generation ...)
- */
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- if (hi == NULL) {
- printk(KERN_ERR "raw1394: attempt to remove unknown host "
- "0x%p\n", host);
- return;
- }
-
- kfree(hi);
-
- atomic_inc(&internal_generation);
-}
-
-static void host_reset(struct hpsb_host *host)
-{
- unsigned long flags;
- struct host_info *hi;
- struct file_info *fi;
- struct pending_request *req;
-
- spin_lock_irqsave(&host_info_lock, flags);
- hi = find_host_info(host);
-
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- if (fi->notification == RAW1394_NOTIFY_ON) {
- req = __alloc_pending_request(GFP_ATOMIC);
-
- if (req != NULL) {
- req->file_info = fi;
- req->req.type = RAW1394_REQ_BUS_RESET;
- req->req.generation =
- get_hpsb_generation(host);
- req->req.misc = (host->node_id << 16)
- | host->node_count;
- if (fi->protocol_version > 3) {
- req->req.misc |=
- (NODEID_TO_NODE
- (host->irm_id)
- << 8);
- }
-
- queue_complete_req(req);
- }
- }
- }
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
-}
-
-static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
- int cts, u8 * data, size_t length)
-{
- unsigned long flags;
- struct host_info *hi;
- struct file_info *fi;
- struct pending_request *req, *req_next;
- struct iso_block_store *ibs = NULL;
- LIST_HEAD(reqs);
-
- if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
- HPSB_INFO("dropped fcp request");
- return;
- }
-
- spin_lock_irqsave(&host_info_lock, flags);
- hi = find_host_info(host);
-
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- if (!fi->fcp_buffer)
- continue;
-
- req = __alloc_pending_request(GFP_ATOMIC);
- if (!req)
- break;
-
- if (!ibs) {
- ibs = kmalloc(sizeof(*ibs) + length,
- GFP_ATOMIC);
- if (!ibs) {
- kfree(req);
- break;
- }
-
- atomic_add(length, &iso_buffer_size);
- atomic_set(&ibs->refcount, 0);
- ibs->data_size = length;
- memcpy(ibs->data, data, length);
- }
-
- atomic_inc(&ibs->refcount);
-
- req->file_info = fi;
- req->ibs = ibs;
- req->data = ibs->data;
- req->req.type = RAW1394_REQ_FCP_REQUEST;
- req->req.generation = get_hpsb_generation(host);
- req->req.misc = nodeid | (direction << 16);
- req->req.recvb = ptr2int(fi->fcp_buffer);
- req->req.length = length;
-
- list_add_tail(&req->list, &reqs);
- }
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- list_for_each_entry_safe(req, req_next, &reqs, list)
- queue_complete_req(req);
-}
-
-#ifdef CONFIG_COMPAT
-struct compat_raw1394_req {
- __u32 type;
- __s32 error;
- __u32 misc;
-
- __u32 generation;
- __u32 length;
-
- __u64 address;
-
- __u64 tag;
-
- __u64 sendb;
- __u64 recvb;
-}
-#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
-__attribute__((packed))
-#endif
-;
-
-static const char __user *raw1394_compat_write(const char __user *buf)
-{
- struct compat_raw1394_req __user *cr = (typeof(cr)) buf;
- struct raw1394_request __user *r;
-
- r = compat_alloc_user_space(sizeof(struct raw1394_request));
-
-#define C(x) __copy_in_user(&r->x, &cr->x, sizeof(r->x))
-
- if (copy_in_user(r, cr, sizeof(struct compat_raw1394_req)) ||
- C(address) ||
- C(tag) ||
- C(sendb) ||
- C(recvb))
- return (__force const char __user *)ERR_PTR(-EFAULT);
-
- return (const char __user *)r;
-}
-#undef C
-
-#define P(x) __put_user(r->x, &cr->x)
-
-static int
-raw1394_compat_read(const char __user *buf, struct raw1394_request *r)
-{
- struct compat_raw1394_req __user *cr = (typeof(cr)) buf;
-
- if (!access_ok(VERIFY_WRITE, cr, sizeof(struct compat_raw1394_req)) ||
- P(type) ||
- P(error) ||
- P(misc) ||
- P(generation) ||
- P(length) ||
- P(address) ||
- P(tag) ||
- P(sendb) ||
- P(recvb))
- return -EFAULT;
-
- return sizeof(struct compat_raw1394_req);
-}
-#undef P
-
-#endif
-
-/* get next completed request (caller must hold fi->reqlists_lock) */
-static inline struct pending_request *__next_complete_req(struct file_info *fi)
-{
- struct list_head *lh;
- struct pending_request *req = NULL;
-
- if (!list_empty(&fi->req_complete)) {
- lh = fi->req_complete.next;
- list_del(lh);
- req = list_entry(lh, struct pending_request, list);
- }
- return req;
-}
-
-/* atomically get next completed request */
-static struct pending_request *next_complete_req(struct file_info *fi)
-{
- unsigned long flags;
- struct pending_request *req;
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- req = __next_complete_req(fi);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
- return req;
-}
-
-static ssize_t raw1394_read(struct file *file, char __user * buffer,
- size_t count, loff_t * offset_is_ignored)
-{
- struct file_info *fi = file->private_data;
- struct pending_request *req;
- ssize_t ret;
-
-#ifdef CONFIG_COMPAT
- if (count == sizeof(struct compat_raw1394_req)) {
- /* ok */
- } else
-#endif
- if (count != sizeof(struct raw1394_request)) {
- return -EINVAL;
- }
-
- if (!access_ok(VERIFY_WRITE, buffer, count)) {
- return -EFAULT;
- }
-
- if (file->f_flags & O_NONBLOCK) {
- if (!(req = next_complete_req(fi)))
- return -EAGAIN;
- } else {
- /*
- * NB: We call the macro wait_event_interruptible() with a
- * condition argument with side effect. This is only possible
- * because the side effect does not occur until the condition
- * became true, and wait_event_interruptible() won't evaluate
- * the condition again after that.
- */
- if (wait_event_interruptible(fi->wait_complete,
- (req = next_complete_req(fi))))
- return -ERESTARTSYS;
- }
-
- if (req->req.length) {
- if (copy_to_user(int2ptr(req->req.recvb), req->data,
- req->req.length)) {
- req->req.error = RAW1394_ERROR_MEMFAULT;
- }
- }
-
-#ifdef CONFIG_COMPAT
- if (count == sizeof(struct compat_raw1394_req) &&
- sizeof(struct compat_raw1394_req) !=
- sizeof(struct raw1394_request)) {
- ret = raw1394_compat_read(buffer, &req->req);
- } else
-#endif
- {
- if (copy_to_user(buffer, &req->req, sizeof(req->req))) {
- ret = -EFAULT;
- goto out;
- }
- ret = (ssize_t) sizeof(struct raw1394_request);
- }
- out:
- free_pending_request(req);
- return ret;
-}
-
-static int state_opened(struct file_info *fi, struct pending_request *req)
-{
- if (req->req.type == RAW1394_REQ_INITIALIZE) {
- switch (req->req.misc) {
- case RAW1394_KERNELAPI_VERSION:
- case 3:
- fi->state = initialized;
- fi->protocol_version = req->req.misc;
- req->req.error = RAW1394_ERROR_NONE;
- req->req.generation = atomic_read(&internal_generation);
- break;
-
- default:
- req->req.error = RAW1394_ERROR_COMPAT;
- req->req.misc = RAW1394_KERNELAPI_VERSION;
- }
- } else {
- req->req.error = RAW1394_ERROR_STATE_ORDER;
- }
-
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
-}
-
-static int state_initialized(struct file_info *fi, struct pending_request *req)
-{
- unsigned long flags;
- struct host_info *hi;
- struct raw1394_khost_list *khl;
-
- if (req->req.generation != atomic_read(&internal_generation)) {
- req->req.error = RAW1394_ERROR_GENERATION;
- req->req.generation = atomic_read(&internal_generation);
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- switch (req->req.type) {
- case RAW1394_REQ_LIST_CARDS:
- spin_lock_irqsave(&host_info_lock, flags);
- khl = kmalloc(sizeof(*khl) * host_count, GFP_ATOMIC);
-
- if (khl) {
- req->req.misc = host_count;
- req->data = (quadlet_t *) khl;
-
- list_for_each_entry(hi, &host_info_list, list) {
- khl->nodes = hi->host->node_count;
- strcpy(khl->name, hi->host->driver->name);
- khl++;
- }
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- if (khl) {
- req->req.error = RAW1394_ERROR_NONE;
- req->req.length = min(req->req.length,
- (u32) (sizeof
- (struct raw1394_khost_list)
- * req->req.misc));
- req->free_data = 1;
- } else {
- return -ENOMEM;
- }
- break;
-
- case RAW1394_REQ_SET_CARD:
- spin_lock_irqsave(&host_info_lock, flags);
- if (req->req.misc >= host_count) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- goto out_set_card;
- }
- list_for_each_entry(hi, &host_info_list, list)
- if (!req->req.misc--)
- break;
- get_device(&hi->host->device); /* FIXME handle failure case */
- list_add_tail(&fi->list, &hi->file_info_list);
-
- /* prevent unloading of the host's low-level driver */
- if (!try_module_get(hi->host->driver->owner)) {
- req->req.error = RAW1394_ERROR_ABORTED;
- goto out_set_card;
- }
- WARN_ON(fi->host);
- fi->host = hi->host;
- fi->state = connected;
-
- req->req.error = RAW1394_ERROR_NONE;
- req->req.generation = get_hpsb_generation(fi->host);
- req->req.misc = (fi->host->node_id << 16)
- | fi->host->node_count;
- if (fi->protocol_version > 3)
- req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
-out_set_card:
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- req->req.length = 0;
- break;
-
- default:
- req->req.error = RAW1394_ERROR_STATE_ORDER;
- req->req.length = 0;
- break;
- }
-
- queue_complete_req(req);
- return 0;
-}
-
-static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
-{
- if (req->req.misc) {
- if (fi->fcp_buffer) {
- req->req.error = RAW1394_ERROR_ALREADY;
- } else {
- fi->fcp_buffer = int2ptr(req->req.recvb);
- }
- } else {
- if (!fi->fcp_buffer) {
- req->req.error = RAW1394_ERROR_ALREADY;
- } else {
- fi->fcp_buffer = NULL;
- }
- }
-
- req->req.length = 0;
- queue_complete_req(req);
-}
-
-static int handle_async_request(struct file_info *fi,
- struct pending_request *req, int node)
-{
- unsigned long flags;
- struct hpsb_packet *packet = NULL;
- u64 addr = req->req.address & 0xffffffffffffULL;
-
- switch (req->req.type) {
- case RAW1394_REQ_ASYNC_READ:
- DBGMSG("read_request called");
- packet =
- hpsb_make_readpacket(fi->host, node, addr, req->req.length);
-
- if (!packet)
- return -ENOMEM;
-
- if (req->req.length == 4)
- req->data = &packet->header[3];
- else
- req->data = packet->data;
-
- break;
-
- case RAW1394_REQ_ASYNC_WRITE:
- DBGMSG("write_request called");
-
- packet = hpsb_make_writepacket(fi->host, node, addr, NULL,
- req->req.length);
- if (!packet)
- return -ENOMEM;
-
- if (req->req.length == 4) {
- if (copy_from_user
- (&packet->header[3], int2ptr(req->req.sendb),
- req->req.length))
- req->req.error = RAW1394_ERROR_MEMFAULT;
- } else {
- if (copy_from_user
- (packet->data, int2ptr(req->req.sendb),
- req->req.length))
- req->req.error = RAW1394_ERROR_MEMFAULT;
- }
-
- req->req.length = 0;
- break;
-
- case RAW1394_REQ_ASYNC_STREAM:
- DBGMSG("stream_request called");
-
- packet =
- hpsb_make_streampacket(fi->host, NULL, req->req.length,
- node & 0x3f /*channel */ ,
- (req->req.misc >> 16) & 0x3,
- req->req.misc & 0xf);
- if (!packet)
- return -ENOMEM;
-
- if (copy_from_user(packet->data, int2ptr(req->req.sendb),
- req->req.length))
- req->req.error = RAW1394_ERROR_MEMFAULT;
-
- req->req.length = 0;
- break;
-
- case RAW1394_REQ_LOCK:
- DBGMSG("lock_request called");
- if ((req->req.misc == EXTCODE_FETCH_ADD)
- || (req->req.misc == EXTCODE_LITTLE_ADD)) {
- if (req->req.length != 4) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- break;
- }
- } else {
- if (req->req.length != 8) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- break;
- }
- }
-
- packet = hpsb_make_lockpacket(fi->host, node, addr,
- req->req.misc, NULL, 0);
- if (!packet)
- return -ENOMEM;
-
- if (copy_from_user(packet->data, int2ptr(req->req.sendb),
- req->req.length)) {
- req->req.error = RAW1394_ERROR_MEMFAULT;
- break;
- }
-
- req->data = packet->data;
- req->req.length = 4;
- break;
-
- case RAW1394_REQ_LOCK64:
- DBGMSG("lock64_request called");
- if ((req->req.misc == EXTCODE_FETCH_ADD)
- || (req->req.misc == EXTCODE_LITTLE_ADD)) {
- if (req->req.length != 8) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- break;
- }
- } else {
- if (req->req.length != 16) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- break;
- }
- }
- packet = hpsb_make_lock64packet(fi->host, node, addr,
- req->req.misc, NULL, 0);
- if (!packet)
- return -ENOMEM;
-
- if (copy_from_user(packet->data, int2ptr(req->req.sendb),
- req->req.length)) {
- req->req.error = RAW1394_ERROR_MEMFAULT;
- break;
- }
-
- req->data = packet->data;
- req->req.length = 8;
- break;
-
- default:
- req->req.error = RAW1394_ERROR_STATE_ORDER;
- }
-
- req->packet = packet;
-
- if (req->req.error) {
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- hpsb_set_packet_complete_task(packet,
- (void (*)(void *))queue_complete_cb, req);
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- list_add_tail(&req->list, &fi->req_pending);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
- packet->generation = req->req.generation;
-
- if (hpsb_send_packet(packet) < 0) {
- req->req.error = RAW1394_ERROR_SEND_ERROR;
- req->req.length = 0;
- hpsb_free_tlabel(packet);
- queue_complete_req(req);
- }
- return 0;
-}
-
-static int handle_async_send(struct file_info *fi, struct pending_request *req)
-{
- unsigned long flags;
- struct hpsb_packet *packet;
- int header_length = req->req.misc & 0xffff;
- int expect_response = req->req.misc >> 16;
- size_t data_size;
-
- if (header_length > req->req.length || header_length < 12 ||
- header_length > FIELD_SIZEOF(struct hpsb_packet, header)) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- data_size = req->req.length - header_length;
- packet = hpsb_alloc_packet(data_size);
- req->packet = packet;
- if (!packet)
- return -ENOMEM;
-
- if (copy_from_user(packet->header, int2ptr(req->req.sendb),
- header_length)) {
- req->req.error = RAW1394_ERROR_MEMFAULT;
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- if (copy_from_user
- (packet->data, int2ptr(req->req.sendb) + header_length,
- data_size)) {
- req->req.error = RAW1394_ERROR_MEMFAULT;
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- packet->type = hpsb_async;
- packet->node_id = packet->header[0] >> 16;
- packet->tcode = (packet->header[0] >> 4) & 0xf;
- packet->tlabel = (packet->header[0] >> 10) & 0x3f;
- packet->host = fi->host;
- packet->expect_response = expect_response;
- packet->header_size = header_length;
- packet->data_size = data_size;
-
- req->req.length = 0;
- hpsb_set_packet_complete_task(packet,
- (void (*)(void *))queue_complete_cb, req);
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- list_add_tail(&req->list, &fi->req_pending);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
- /* Update the generation of the packet just before sending. */
- packet->generation = req->req.generation;
-
- if (hpsb_send_packet(packet) < 0) {
- req->req.error = RAW1394_ERROR_SEND_ERROR;
- queue_complete_req(req);
- }
-
- return 0;
-}
-
-static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
- u64 addr, size_t length, u16 flags)
-{
- unsigned long irqflags;
- struct pending_request *req;
- struct host_info *hi;
- struct file_info *fi = NULL;
- struct list_head *entry;
- struct arm_addr *arm_addr = NULL;
- struct arm_request *arm_req = NULL;
- struct arm_response *arm_resp = NULL;
- int found = 0, size = 0, rcode = -1;
- struct arm_request_response *arm_req_resp = NULL;
-
- DBGMSG("arm_read called by node: %X "
- "addr: %4.4x %8.8x length: %Zu", nodeid,
- (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
- length);
- spin_lock_irqsave(&host_info_lock, irqflags);
- hi = find_host_info(host); /* search address-entry */
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr,
- addr_list);
- if (((arm_addr->start) <= (addr))
- && ((arm_addr->end) >= (addr + length))) {
- found = 1;
- break;
- }
- entry = entry->next;
- }
- if (found) {
- break;
- }
- }
- }
- rcode = -1;
- if (!found) {
- printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
- " -> rcode_address_error\n");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_ADDRESS_ERROR);
- } else {
- DBGMSG("arm_read addr_entry FOUND");
- }
- if (arm_addr->rec_length < length) {
- DBGMSG("arm_read blocklength too big -> rcode_data_error");
- rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
- }
- if (rcode == -1) {
- if (arm_addr->access_rights & ARM_READ) {
- if (!(arm_addr->client_transactions & ARM_READ)) {
- memcpy(buffer,
- (arm_addr->addr_space_buffer) + (addr -
- (arm_addr->
- start)),
- length);
- DBGMSG("arm_read -> (rcode_complete)");
- rcode = RCODE_COMPLETE;
- }
- } else {
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- DBGMSG("arm_read -> rcode_type_error (access denied)");
- }
- }
- if (arm_addr->notification_options & ARM_READ) {
- DBGMSG("arm_read -> entering notification-section");
- req = __alloc_pending_request(GFP_ATOMIC);
- if (!req) {
- DBGMSG("arm_read -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- if (rcode == RCODE_COMPLETE) {
- size =
- sizeof(struct arm_request) +
- sizeof(struct arm_response) +
- length * sizeof(byte_t) +
- sizeof(struct arm_request_response);
- } else {
- size =
- sizeof(struct arm_request) +
- sizeof(struct arm_response) +
- sizeof(struct arm_request_response);
- }
- req->data = kmalloc(size, GFP_ATOMIC);
- if (!(req->data)) {
- free_pending_request(req);
- DBGMSG("arm_read -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- req->free_data = 1;
- req->file_info = fi;
- req->req.type = RAW1394_REQ_ARM;
- req->req.generation = get_hpsb_generation(host);
- req->req.misc =
- (((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF));
- req->req.tag = arm_addr->arm_tag;
- req->req.recvb = arm_addr->recvb;
- req->req.length = size;
- arm_req_resp = (struct arm_request_response *)(req->data);
- arm_req = (struct arm_request *)((byte_t *) (req->data) +
- (sizeof
- (struct
- arm_request_response)));
- arm_resp =
- (struct arm_response *)((byte_t *) (arm_req) +
- (sizeof(struct arm_request)));
- arm_req->buffer = NULL;
- arm_resp->buffer = NULL;
- if (rcode == RCODE_COMPLETE) {
- byte_t *buf =
- (byte_t *) arm_resp + sizeof(struct arm_response);
- memcpy(buf,
- (arm_addr->addr_space_buffer) + (addr -
- (arm_addr->
- start)),
- length);
- arm_resp->buffer =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response));
- }
- arm_resp->buffer_length =
- (rcode == RCODE_COMPLETE) ? length : 0;
- arm_resp->response_code = rcode;
- arm_req->buffer_length = 0;
- arm_req->generation = req->req.generation;
- arm_req->extended_transaction_code = 0;
- arm_req->destination_offset = addr;
- arm_req->source_nodeid = nodeid;
- arm_req->destination_nodeid = host->node_id;
- arm_req->tlabel = (flags >> 10) & 0x3f;
- arm_req->tcode = (flags >> 4) & 0x0f;
- arm_req_resp->request = int2ptr((arm_addr->recvb) +
- sizeof(struct
- arm_request_response));
- arm_req_resp->response =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request));
- queue_complete_req(req);
- }
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (rcode);
-}
-
-static int arm_write(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t * data, u64 addr, size_t length, u16 flags)
-{
- unsigned long irqflags;
- struct pending_request *req;
- struct host_info *hi;
- struct file_info *fi = NULL;
- struct list_head *entry;
- struct arm_addr *arm_addr = NULL;
- struct arm_request *arm_req = NULL;
- struct arm_response *arm_resp = NULL;
- int found = 0, size = 0, rcode = -1;
- struct arm_request_response *arm_req_resp = NULL;
-
- DBGMSG("arm_write called by node: %X "
- "addr: %4.4x %8.8x length: %Zu", nodeid,
- (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
- length);
- spin_lock_irqsave(&host_info_lock, irqflags);
- hi = find_host_info(host); /* search address-entry */
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr,
- addr_list);
- if (((arm_addr->start) <= (addr))
- && ((arm_addr->end) >= (addr + length))) {
- found = 1;
- break;
- }
- entry = entry->next;
- }
- if (found) {
- break;
- }
- }
- }
- rcode = -1;
- if (!found) {
- printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found"
- " -> rcode_address_error\n");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_ADDRESS_ERROR);
- } else {
- DBGMSG("arm_write addr_entry FOUND");
- }
- if (arm_addr->rec_length < length) {
- DBGMSG("arm_write blocklength too big -> rcode_data_error");
- rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
- }
- if (rcode == -1) {
- if (arm_addr->access_rights & ARM_WRITE) {
- if (!(arm_addr->client_transactions & ARM_WRITE)) {
- memcpy((arm_addr->addr_space_buffer) +
- (addr - (arm_addr->start)), data,
- length);
- DBGMSG("arm_write -> (rcode_complete)");
- rcode = RCODE_COMPLETE;
- }
- } else {
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- DBGMSG("arm_write -> rcode_type_error (access denied)");
- }
- }
- if (arm_addr->notification_options & ARM_WRITE) {
- DBGMSG("arm_write -> entering notification-section");
- req = __alloc_pending_request(GFP_ATOMIC);
- if (!req) {
- DBGMSG("arm_write -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request my be retried */
- }
- size =
- sizeof(struct arm_request) + sizeof(struct arm_response) +
- (length) * sizeof(byte_t) +
- sizeof(struct arm_request_response);
- req->data = kmalloc(size, GFP_ATOMIC);
- if (!(req->data)) {
- free_pending_request(req);
- DBGMSG("arm_write -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- req->free_data = 1;
- req->file_info = fi;
- req->req.type = RAW1394_REQ_ARM;
- req->req.generation = get_hpsb_generation(host);
- req->req.misc =
- (((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF));
- req->req.tag = arm_addr->arm_tag;
- req->req.recvb = arm_addr->recvb;
- req->req.length = size;
- arm_req_resp = (struct arm_request_response *)(req->data);
- arm_req = (struct arm_request *)((byte_t *) (req->data) +
- (sizeof
- (struct
- arm_request_response)));
- arm_resp =
- (struct arm_response *)((byte_t *) (arm_req) +
- (sizeof(struct arm_request)));
- arm_resp->buffer = NULL;
- memcpy((byte_t *) arm_resp + sizeof(struct arm_response),
- data, length);
- arm_req->buffer = int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response));
- arm_req->buffer_length = length;
- arm_req->generation = req->req.generation;
- arm_req->extended_transaction_code = 0;
- arm_req->destination_offset = addr;
- arm_req->source_nodeid = nodeid;
- arm_req->destination_nodeid = destid;
- arm_req->tlabel = (flags >> 10) & 0x3f;
- arm_req->tcode = (flags >> 4) & 0x0f;
- arm_resp->buffer_length = 0;
- arm_resp->response_code = rcode;
- arm_req_resp->request = int2ptr((arm_addr->recvb) +
- sizeof(struct
- arm_request_response));
- arm_req_resp->response =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request));
- queue_complete_req(req);
- }
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (rcode);
-}
-
-static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
- u16 flags)
-{
- unsigned long irqflags;
- struct pending_request *req;
- struct host_info *hi;
- struct file_info *fi = NULL;
- struct list_head *entry;
- struct arm_addr *arm_addr = NULL;
- struct arm_request *arm_req = NULL;
- struct arm_response *arm_resp = NULL;
- int found = 0, size = 0, rcode = -1;
- quadlet_t old, new;
- struct arm_request_response *arm_req_resp = NULL;
-
- if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
- ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
- DBGMSG("arm_lock called by node: %X "
- "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X",
- nodeid, (u16) ((addr >> 32) & 0xFFFF),
- (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF,
- be32_to_cpu(data));
- } else {
- DBGMSG("arm_lock called by node: %X "
- "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X",
- nodeid, (u16) ((addr >> 32) & 0xFFFF),
- (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF,
- be32_to_cpu(data), be32_to_cpu(arg));
- }
- spin_lock_irqsave(&host_info_lock, irqflags);
- hi = find_host_info(host); /* search address-entry */
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr,
- addr_list);
- if (((arm_addr->start) <= (addr))
- && ((arm_addr->end) >=
- (addr + sizeof(*store)))) {
- found = 1;
- break;
- }
- entry = entry->next;
- }
- if (found) {
- break;
- }
- }
- }
- rcode = -1;
- if (!found) {
- printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found"
- " -> rcode_address_error\n");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_ADDRESS_ERROR);
- } else {
- DBGMSG("arm_lock addr_entry FOUND");
- }
- if (rcode == -1) {
- if (arm_addr->access_rights & ARM_LOCK) {
- if (!(arm_addr->client_transactions & ARM_LOCK)) {
- memcpy(&old,
- (arm_addr->addr_space_buffer) + (addr -
- (arm_addr->
- start)),
- sizeof(old));
- switch (ext_tcode) {
- case (EXTCODE_MASK_SWAP):
- new = data | (old & ~arg);
- break;
- case (EXTCODE_COMPARE_SWAP):
- if (old == arg) {
- new = data;
- } else {
- new = old;
- }
- break;
- case (EXTCODE_FETCH_ADD):
- new =
- cpu_to_be32(be32_to_cpu(data) +
- be32_to_cpu(old));
- break;
- case (EXTCODE_LITTLE_ADD):
- new =
- cpu_to_le32(le32_to_cpu(data) +
- le32_to_cpu(old));
- break;
- case (EXTCODE_BOUNDED_ADD):
- if (old != arg) {
- new =
- cpu_to_be32(be32_to_cpu
- (data) +
- be32_to_cpu
- (old));
- } else {
- new = old;
- }
- break;
- case (EXTCODE_WRAP_ADD):
- if (old != arg) {
- new =
- cpu_to_be32(be32_to_cpu
- (data) +
- be32_to_cpu
- (old));
- } else {
- new = data;
- }
- break;
- default:
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- printk(KERN_ERR
- "raw1394: arm_lock FAILED "
- "ext_tcode not allowed -> rcode_type_error\n");
- break;
- } /*switch */
- if (rcode == -1) {
- DBGMSG("arm_lock -> (rcode_complete)");
- rcode = RCODE_COMPLETE;
- memcpy(store, &old, sizeof(*store));
- memcpy((arm_addr->addr_space_buffer) +
- (addr - (arm_addr->start)),
- &new, sizeof(*store));
- }
- }
- } else {
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- DBGMSG("arm_lock -> rcode_type_error (access denied)");
- }
- }
- if (arm_addr->notification_options & ARM_LOCK) {
- byte_t *buf1, *buf2;
- DBGMSG("arm_lock -> entering notification-section");
- req = __alloc_pending_request(GFP_ATOMIC);
- if (!req) {
- DBGMSG("arm_lock -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response); /* maximum */
- req->data = kmalloc(size, GFP_ATOMIC);
- if (!(req->data)) {
- free_pending_request(req);
- DBGMSG("arm_lock -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- req->free_data = 1;
- arm_req_resp = (struct arm_request_response *)(req->data);
- arm_req = (struct arm_request *)((byte_t *) (req->data) +
- (sizeof
- (struct
- arm_request_response)));
- arm_resp =
- (struct arm_response *)((byte_t *) (arm_req) +
- (sizeof(struct arm_request)));
- buf1 = (byte_t *) arm_resp + sizeof(struct arm_response);
- buf2 = buf1 + 2 * sizeof(*store);
- if ((ext_tcode == EXTCODE_FETCH_ADD) ||
- (ext_tcode == EXTCODE_LITTLE_ADD)) {
- arm_req->buffer_length = sizeof(*store);
- memcpy(buf1, &data, sizeof(*store));
-
- } else {
- arm_req->buffer_length = 2 * sizeof(*store);
- memcpy(buf1, &arg, sizeof(*store));
- memcpy(buf1 + sizeof(*store), &data, sizeof(*store));
- }
- if (rcode == RCODE_COMPLETE) {
- arm_resp->buffer_length = sizeof(*store);
- memcpy(buf2, &old, sizeof(*store));
- } else {
- arm_resp->buffer_length = 0;
- }
- req->file_info = fi;
- req->req.type = RAW1394_REQ_ARM;
- req->req.generation = get_hpsb_generation(host);
- req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) |
- (ARM_LOCK & 0xFF));
- req->req.tag = arm_addr->arm_tag;
- req->req.recvb = arm_addr->recvb;
- req->req.length = size;
- arm_req->generation = req->req.generation;
- arm_req->extended_transaction_code = ext_tcode;
- arm_req->destination_offset = addr;
- arm_req->source_nodeid = nodeid;
- arm_req->destination_nodeid = host->node_id;
- arm_req->tlabel = (flags >> 10) & 0x3f;
- arm_req->tcode = (flags >> 4) & 0x0f;
- arm_resp->response_code = rcode;
- arm_req_resp->request = int2ptr((arm_addr->recvb) +
- sizeof(struct
- arm_request_response));
- arm_req_resp->response =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request));
- arm_req->buffer =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response));
- arm_resp->buffer =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response) + 2 * sizeof(*store));
- queue_complete_req(req);
- }
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (rcode);
-}
-
-static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
- u16 flags)
-{
- unsigned long irqflags;
- struct pending_request *req;
- struct host_info *hi;
- struct file_info *fi = NULL;
- struct list_head *entry;
- struct arm_addr *arm_addr = NULL;
- struct arm_request *arm_req = NULL;
- struct arm_response *arm_resp = NULL;
- int found = 0, size = 0, rcode = -1;
- octlet_t old, new;
- struct arm_request_response *arm_req_resp = NULL;
-
- if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
- ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
- DBGMSG("arm_lock64 called by node: %X "
- "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ",
- nodeid, (u16) ((addr >> 32) & 0xFFFF),
- (u32) (addr & 0xFFFFFFFF),
- ext_tcode & 0xFF,
- (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
- (u32) (be64_to_cpu(data) & 0xFFFFFFFF));
- } else {
- DBGMSG("arm_lock64 called by node: %X "
- "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: "
- "%8.8X %8.8X ",
- nodeid, (u16) ((addr >> 32) & 0xFFFF),
- (u32) (addr & 0xFFFFFFFF),
- ext_tcode & 0xFF,
- (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
- (u32) (be64_to_cpu(data) & 0xFFFFFFFF),
- (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF),
- (u32) (be64_to_cpu(arg) & 0xFFFFFFFF));
- }
- spin_lock_irqsave(&host_info_lock, irqflags);
- hi = find_host_info(host); /* search addressentry in file_info's for host */
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr,
- addr_list);
- if (((arm_addr->start) <= (addr))
- && ((arm_addr->end) >=
- (addr + sizeof(*store)))) {
- found = 1;
- break;
- }
- entry = entry->next;
- }
- if (found) {
- break;
- }
- }
- }
- rcode = -1;
- if (!found) {
- printk(KERN_ERR
- "raw1394: arm_lock64 FAILED addr_entry not found"
- " -> rcode_address_error\n");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_ADDRESS_ERROR);
- } else {
- DBGMSG("arm_lock64 addr_entry FOUND");
- }
- if (rcode == -1) {
- if (arm_addr->access_rights & ARM_LOCK) {
- if (!(arm_addr->client_transactions & ARM_LOCK)) {
- memcpy(&old,
- (arm_addr->addr_space_buffer) + (addr -
- (arm_addr->
- start)),
- sizeof(old));
- switch (ext_tcode) {
- case (EXTCODE_MASK_SWAP):
- new = data | (old & ~arg);
- break;
- case (EXTCODE_COMPARE_SWAP):
- if (old == arg) {
- new = data;
- } else {
- new = old;
- }
- break;
- case (EXTCODE_FETCH_ADD):
- new =
- cpu_to_be64(be64_to_cpu(data) +
- be64_to_cpu(old));
- break;
- case (EXTCODE_LITTLE_ADD):
- new =
- cpu_to_le64(le64_to_cpu(data) +
- le64_to_cpu(old));
- break;
- case (EXTCODE_BOUNDED_ADD):
- if (old != arg) {
- new =
- cpu_to_be64(be64_to_cpu
- (data) +
- be64_to_cpu
- (old));
- } else {
- new = old;
- }
- break;
- case (EXTCODE_WRAP_ADD):
- if (old != arg) {
- new =
- cpu_to_be64(be64_to_cpu
- (data) +
- be64_to_cpu
- (old));
- } else {
- new = data;
- }
- break;
- default:
- printk(KERN_ERR
- "raw1394: arm_lock64 FAILED "
- "ext_tcode not allowed -> rcode_type_error\n");
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- break;
- } /*switch */
- if (rcode == -1) {
- DBGMSG
- ("arm_lock64 -> (rcode_complete)");
- rcode = RCODE_COMPLETE;
- memcpy(store, &old, sizeof(*store));
- memcpy((arm_addr->addr_space_buffer) +
- (addr - (arm_addr->start)),
- &new, sizeof(*store));
- }
- }
- } else {
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- DBGMSG
- ("arm_lock64 -> rcode_type_error (access denied)");
- }
- }
- if (arm_addr->notification_options & ARM_LOCK) {
- byte_t *buf1, *buf2;
- DBGMSG("arm_lock64 -> entering notification-section");
- req = __alloc_pending_request(GFP_ATOMIC);
- if (!req) {
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- DBGMSG("arm_lock64 -> rcode_conflict_error");
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response); /* maximum */
- req->data = kmalloc(size, GFP_ATOMIC);
- if (!(req->data)) {
- free_pending_request(req);
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- DBGMSG("arm_lock64 -> rcode_conflict_error");
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- req->free_data = 1;
- arm_req_resp = (struct arm_request_response *)(req->data);
- arm_req = (struct arm_request *)((byte_t *) (req->data) +
- (sizeof
- (struct
- arm_request_response)));
- arm_resp =
- (struct arm_response *)((byte_t *) (arm_req) +
- (sizeof(struct arm_request)));
- buf1 = (byte_t *) arm_resp + sizeof(struct arm_response);
- buf2 = buf1 + 2 * sizeof(*store);
- if ((ext_tcode == EXTCODE_FETCH_ADD) ||
- (ext_tcode == EXTCODE_LITTLE_ADD)) {
- arm_req->buffer_length = sizeof(*store);
- memcpy(buf1, &data, sizeof(*store));
-
- } else {
- arm_req->buffer_length = 2 * sizeof(*store);
- memcpy(buf1, &arg, sizeof(*store));
- memcpy(buf1 + sizeof(*store), &data, sizeof(*store));
- }
- if (rcode == RCODE_COMPLETE) {
- arm_resp->buffer_length = sizeof(*store);
- memcpy(buf2, &old, sizeof(*store));
- } else {
- arm_resp->buffer_length = 0;
- }
- req->file_info = fi;
- req->req.type = RAW1394_REQ_ARM;
- req->req.generation = get_hpsb_generation(host);
- req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) |
- (ARM_LOCK & 0xFF));
- req->req.tag = arm_addr->arm_tag;
- req->req.recvb = arm_addr->recvb;
- req->req.length = size;
- arm_req->generation = req->req.generation;
- arm_req->extended_transaction_code = ext_tcode;
- arm_req->destination_offset = addr;
- arm_req->source_nodeid = nodeid;
- arm_req->destination_nodeid = host->node_id;
- arm_req->tlabel = (flags >> 10) & 0x3f;
- arm_req->tcode = (flags >> 4) & 0x0f;
- arm_resp->response_code = rcode;
- arm_req_resp->request = int2ptr((arm_addr->recvb) +
- sizeof(struct
- arm_request_response));
- arm_req_resp->response =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request));
- arm_req->buffer =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response));
- arm_resp->buffer =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response) + 2 * sizeof(*store));
- queue_complete_req(req);
- }
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (rcode);
-}
-
-static int arm_register(struct file_info *fi, struct pending_request *req)
-{
- int retval;
- struct arm_addr *addr;
- struct host_info *hi;
- struct file_info *fi_hlp = NULL;
- struct list_head *entry;
- struct arm_addr *arm_addr = NULL;
- int same_host, another_host;
- unsigned long flags;
-
- DBGMSG("arm_register called "
- "addr(Offset): %8.8x %8.8x length: %u "
- "rights: %2.2X notify: %2.2X "
- "max_blk_len: %4.4X",
- (u32) ((req->req.address >> 32) & 0xFFFF),
- (u32) (req->req.address & 0xFFFFFFFF),
- req->req.length, ((req->req.misc >> 8) & 0xFF),
- (req->req.misc & 0xFF), ((req->req.misc >> 16) & 0xFFFF));
- /* check addressrange */
- if ((((req->req.address) & ~(0xFFFFFFFFFFFFULL)) != 0) ||
- (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFFULL)) !=
- 0)) {
- req->req.length = 0;
- return (-EINVAL);
- }
- /* addr-list-entry for fileinfo */
- addr = kmalloc(sizeof(*addr), GFP_KERNEL);
- if (!addr) {
- req->req.length = 0;
- return (-ENOMEM);
- }
- /* allocation of addr_space_buffer */
- addr->addr_space_buffer = vmalloc(req->req.length);
- if (!(addr->addr_space_buffer)) {
- kfree(addr);
- req->req.length = 0;
- return (-ENOMEM);
- }
- /* initialization of addr_space_buffer */
- if ((req->req.sendb) == (unsigned long)NULL) {
- /* init: set 0 */
- memset(addr->addr_space_buffer, 0, req->req.length);
- } else {
- /* init: user -> kernel */
- if (copy_from_user
- (addr->addr_space_buffer, int2ptr(req->req.sendb),
- req->req.length)) {
- vfree(addr->addr_space_buffer);
- kfree(addr);
- return (-EFAULT);
- }
- }
- INIT_LIST_HEAD(&addr->addr_list);
- addr->arm_tag = req->req.tag;
- addr->start = req->req.address;
- addr->end = req->req.address + req->req.length;
- addr->access_rights = (u8) (req->req.misc & 0x0F);
- addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F);
- addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F);
- addr->access_rights |= addr->client_transactions;
- addr->notification_options |= addr->client_transactions;
- addr->recvb = req->req.recvb;
- addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
-
- spin_lock_irqsave(&host_info_lock, flags);
- hi = find_host_info(fi->host);
- same_host = 0;
- another_host = 0;
- /* same host with address-entry containing same addressrange ? */
- list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
- entry = fi_hlp->addr_list.next;
- while (entry != &(fi_hlp->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr, addr_list);
- if ((arm_addr->start == addr->start)
- && (arm_addr->end == addr->end)) {
- DBGMSG("same host ownes same "
- "addressrange -> EALREADY");
- same_host = 1;
- break;
- }
- entry = entry->next;
- }
- if (same_host) {
- break;
- }
- }
- if (same_host) {
- /* addressrange occupied by same host */
- spin_unlock_irqrestore(&host_info_lock, flags);
- vfree(addr->addr_space_buffer);
- kfree(addr);
- return (-EALREADY);
- }
- /* another host with valid address-entry containing same addressrange */
- list_for_each_entry(hi, &host_info_list, list) {
- if (hi->host != fi->host) {
- list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
- entry = fi_hlp->addr_list.next;
- while (entry != &(fi_hlp->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr,
- addr_list);
- if ((arm_addr->start == addr->start)
- && (arm_addr->end == addr->end)) {
- DBGMSG
- ("another host ownes same "
- "addressrange");
- another_host = 1;
- break;
- }
- entry = entry->next;
- }
- if (another_host) {
- break;
- }
- }
- }
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- if (another_host) {
- DBGMSG("another hosts entry is valid -> SUCCESS");
- if (copy_to_user(int2ptr(req->req.recvb),
- &addr->start, sizeof(u64))) {
- printk(KERN_ERR "raw1394: arm_register failed "
- " address-range-entry is invalid -> EFAULT !!!\n");
- vfree(addr->addr_space_buffer);
- kfree(addr);
- return (-EFAULT);
- }
- free_pending_request(req); /* immediate success or fail */
- /* INSERT ENTRY */
- spin_lock_irqsave(&host_info_lock, flags);
- list_add_tail(&addr->addr_list, &fi->addr_list);
- spin_unlock_irqrestore(&host_info_lock, flags);
- return 0;
- }
- retval =
- hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops,
- req->req.address,
- req->req.address + req->req.length);
- if (retval) {
- /* INSERT ENTRY */
- spin_lock_irqsave(&host_info_lock, flags);
- list_add_tail(&addr->addr_list, &fi->addr_list);
- spin_unlock_irqrestore(&host_info_lock, flags);
- } else {
- DBGMSG("arm_register failed errno: %d \n", retval);
- vfree(addr->addr_space_buffer);
- kfree(addr);
- return (-EALREADY);
- }
- free_pending_request(req); /* immediate success or fail */
- return 0;
-}
-
-static int arm_unregister(struct file_info *fi, struct pending_request *req)
-{
- int found = 0;
- int retval = 0;
- struct list_head *entry;
- struct arm_addr *addr = NULL;
- struct host_info *hi;
- struct file_info *fi_hlp = NULL;
- struct arm_addr *arm_addr = NULL;
- int another_host;
- unsigned long flags;
-
- DBGMSG("arm_Unregister called addr(Offset): "
- "%8.8x %8.8x",
- (u32) ((req->req.address >> 32) & 0xFFFF),
- (u32) (req->req.address & 0xFFFFFFFF));
- spin_lock_irqsave(&host_info_lock, flags);
- /* get addr */
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- addr = list_entry(entry, struct arm_addr, addr_list);
- if (addr->start == req->req.address) {
- found = 1;
- break;
- }
- entry = entry->next;
- }
- if (!found) {
- DBGMSG("arm_Unregister addr not found");
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
- }
- DBGMSG("arm_Unregister addr found");
- another_host = 0;
- /* another host with valid address-entry containing
- same addressrange */
- list_for_each_entry(hi, &host_info_list, list) {
- if (hi->host != fi->host) {
- list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
- entry = fi_hlp->addr_list.next;
- while (entry != &(fi_hlp->addr_list)) {
- arm_addr = list_entry(entry,
- struct arm_addr,
- addr_list);
- if (arm_addr->start == addr->start) {
- DBGMSG("another host ownes "
- "same addressrange");
- another_host = 1;
- break;
- }
- entry = entry->next;
- }
- if (another_host) {
- break;
- }
- }
- }
- }
- if (another_host) {
- DBGMSG("delete entry from list -> success");
- list_del(&addr->addr_list);
- spin_unlock_irqrestore(&host_info_lock, flags);
- vfree(addr->addr_space_buffer);
- kfree(addr);
- free_pending_request(req); /* immediate success or fail */
- return 0;
- }
- retval =
- hpsb_unregister_addrspace(&raw1394_highlevel, fi->host,
- addr->start);
- if (!retval) {
- printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
- }
- DBGMSG("delete entry from list -> success");
- list_del(&addr->addr_list);
- spin_unlock_irqrestore(&host_info_lock, flags);
- vfree(addr->addr_space_buffer);
- kfree(addr);
- free_pending_request(req); /* immediate success or fail */
- return 0;
-}
-
-/* Copy data from ARM buffer(s) to user buffer. */
-static int arm_get_buf(struct file_info *fi, struct pending_request *req)
-{
- struct arm_addr *arm_addr = NULL;
- unsigned long flags;
- unsigned long offset;
-
- struct list_head *entry;
-
- DBGMSG("arm_get_buf "
- "addr(Offset): %04X %08X length: %u",
- (u32) ((req->req.address >> 32) & 0xFFFF),
- (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);
-
- spin_lock_irqsave(&host_info_lock, flags);
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr = list_entry(entry, struct arm_addr, addr_list);
- if ((arm_addr->start <= req->req.address) &&
- (arm_addr->end > req->req.address)) {
- if (req->req.address + req->req.length <= arm_addr->end) {
- offset = req->req.address - arm_addr->start;
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- DBGMSG
- ("arm_get_buf copy_to_user( %08X, %p, %u )",
- (u32) req->req.recvb,
- arm_addr->addr_space_buffer + offset,
- (u32) req->req.length);
- if (copy_to_user
- (int2ptr(req->req.recvb),
- arm_addr->addr_space_buffer + offset,
- req->req.length))
- return (-EFAULT);
-
- /* We have to free the request, because we
- * queue no response, and therefore nobody
- * will free it. */
- free_pending_request(req);
- return 0;
- } else {
- DBGMSG("arm_get_buf request exceeded mapping");
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
- }
- }
- entry = entry->next;
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
-}
-
-/* Copy data from user buffer to ARM buffer(s). */
-static int arm_set_buf(struct file_info *fi, struct pending_request *req)
-{
- struct arm_addr *arm_addr = NULL;
- unsigned long flags;
- unsigned long offset;
-
- struct list_head *entry;
-
- DBGMSG("arm_set_buf "
- "addr(Offset): %04X %08X length: %u",
- (u32) ((req->req.address >> 32) & 0xFFFF),
- (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);
-
- spin_lock_irqsave(&host_info_lock, flags);
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr = list_entry(entry, struct arm_addr, addr_list);
- if ((arm_addr->start <= req->req.address) &&
- (arm_addr->end > req->req.address)) {
- if (req->req.address + req->req.length <= arm_addr->end) {
- offset = req->req.address - arm_addr->start;
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- DBGMSG
- ("arm_set_buf copy_from_user( %p, %08X, %u )",
- arm_addr->addr_space_buffer + offset,
- (u32) req->req.sendb,
- (u32) req->req.length);
- if (copy_from_user
- (arm_addr->addr_space_buffer + offset,
- int2ptr(req->req.sendb),
- req->req.length))
- return (-EFAULT);
-
- /* We have to free the request, because we
- * queue no response, and therefore nobody
- * will free it. */
- free_pending_request(req);
- return 0;
- } else {
- DBGMSG("arm_set_buf request exceeded mapping");
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
- }
- }
- entry = entry->next;
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
-}
-
-static int reset_notification(struct file_info *fi, struct pending_request *req)
-{
- DBGMSG("reset_notification called - switch %s ",
- (req->req.misc == RAW1394_NOTIFY_OFF) ? "OFF" : "ON");
- if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
- (req->req.misc == RAW1394_NOTIFY_ON)) {
- fi->notification = (u8) req->req.misc;
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
- return 0;
- }
- /* error EINVAL (22) invalid argument */
- return (-EINVAL);
-}
-
-static int write_phypacket(struct file_info *fi, struct pending_request *req)
-{
- struct hpsb_packet *packet = NULL;
- int retval = 0;
- quadlet_t data;
- unsigned long flags;
-
- data = be32_to_cpu((u32) req->req.sendb);
- DBGMSG("write_phypacket called - quadlet 0x%8.8x ", data);
- packet = hpsb_make_phypacket(fi->host, data);
- if (!packet)
- return -ENOMEM;
- req->req.length = 0;
- req->packet = packet;
- hpsb_set_packet_complete_task(packet,
- (void (*)(void *))queue_complete_cb, req);
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- list_add_tail(&req->list, &fi->req_pending);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
- packet->generation = req->req.generation;
- retval = hpsb_send_packet(packet);
- DBGMSG("write_phypacket send_packet called => retval: %d ", retval);
- if (retval < 0) {
- req->req.error = RAW1394_ERROR_SEND_ERROR;
- req->req.length = 0;
- queue_complete_req(req);
- }
- return 0;
-}
-
-static int get_config_rom(struct file_info *fi, struct pending_request *req)
-{
- int ret = 0;
- quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
- int status;
-
- if (!data)
- return -ENOMEM;
-
- status =
- csr1212_read(fi->host->csr.rom, CSR1212_CONFIG_ROM_SPACE_OFFSET,
- data, req->req.length);
- if (copy_to_user(int2ptr(req->req.recvb), data, req->req.length))
- ret = -EFAULT;
- if (copy_to_user
- (int2ptr(req->req.tag), &fi->host->csr.rom->cache_head->len,
- sizeof(fi->host->csr.rom->cache_head->len)))
- ret = -EFAULT;
- if (copy_to_user(int2ptr(req->req.address), &fi->host->csr.generation,
- sizeof(fi->host->csr.generation)))
- ret = -EFAULT;
- if (copy_to_user(int2ptr(req->req.sendb), &status, sizeof(status)))
- ret = -EFAULT;
- kfree(data);
- if (ret >= 0) {
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
- }
- return ret;
-}
-
-static int update_config_rom(struct file_info *fi, struct pending_request *req)
-{
- int ret = 0;
- quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- if (copy_from_user(data, int2ptr(req->req.sendb), req->req.length)) {
- ret = -EFAULT;
- } else {
- int status = hpsb_update_config_rom(fi->host,
- data, req->req.length,
- (unsigned char)req->req.
- misc);
- if (copy_to_user
- (int2ptr(req->req.recvb), &status, sizeof(status)))
- ret = -ENOMEM;
- }
- kfree(data);
- if (ret >= 0) {
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
- fi->cfgrom_upd = 1;
- }
- return ret;
-}
-
-static int modify_config_rom(struct file_info *fi, struct pending_request *req)
-{
- struct csr1212_keyval *kv;
- struct csr1212_csr_rom_cache *cache;
- struct csr1212_dentry *dentry;
- u32 dr;
- int ret = 0;
-
- if (req->req.misc == ~0) {
- if (req->req.length == 0)
- return -EINVAL;
-
- /* Find an unused slot */
- for (dr = 0;
- dr < RAW1394_MAX_USER_CSR_DIRS && fi->csr1212_dirs[dr];
- dr++) ;
-
- if (dr == RAW1394_MAX_USER_CSR_DIRS)
- return -ENOMEM;
-
- fi->csr1212_dirs[dr] =
- csr1212_new_directory(CSR1212_KV_ID_VENDOR);
- if (!fi->csr1212_dirs[dr])
- return -ENOMEM;
- } else {
- dr = req->req.misc;
- if (!fi->csr1212_dirs[dr])
- return -EINVAL;
-
- /* Delete old stuff */
- for (dentry =
- fi->csr1212_dirs[dr]->value.directory.dentries_head;
- dentry; dentry = dentry->next) {
- csr1212_detach_keyval_from_directory(fi->host->csr.rom->
- root_kv,
- dentry->kv);
- }
-
- if (req->req.length == 0) {
- csr1212_release_keyval(fi->csr1212_dirs[dr]);
- fi->csr1212_dirs[dr] = NULL;
-
- hpsb_update_config_rom_image(fi->host);
- free_pending_request(req);
- return 0;
- }
- }
-
- cache = csr1212_rom_cache_malloc(0, req->req.length);
- if (!cache) {
- csr1212_release_keyval(fi->csr1212_dirs[dr]);
- fi->csr1212_dirs[dr] = NULL;
- return -ENOMEM;
- }
-
- cache->filled_head = kmalloc(sizeof(*cache->filled_head), GFP_KERNEL);
- if (!cache->filled_head) {
- csr1212_release_keyval(fi->csr1212_dirs[dr]);
- fi->csr1212_dirs[dr] = NULL;
- CSR1212_FREE(cache);
- return -ENOMEM;
- }
- cache->filled_tail = cache->filled_head;
-
- if (copy_from_user(cache->data, int2ptr(req->req.sendb),
- req->req.length)) {
- csr1212_release_keyval(fi->csr1212_dirs[dr]);
- fi->csr1212_dirs[dr] = NULL;
- ret = -EFAULT;
- } else {
- cache->len = req->req.length;
- cache->filled_head->offset_start = 0;
- cache->filled_head->offset_end = cache->size - 1;
-
- cache->layout_head = cache->layout_tail = fi->csr1212_dirs[dr];
-
- ret = CSR1212_SUCCESS;
- /* parse all the items */
- for (kv = cache->layout_head; ret == CSR1212_SUCCESS && kv;
- kv = kv->next) {
- ret = csr1212_parse_keyval(kv, cache);
- }
-
- /* attach top level items to the root directory */
- for (dentry =
- fi->csr1212_dirs[dr]->value.directory.dentries_head;
- ret == CSR1212_SUCCESS && dentry; dentry = dentry->next) {
- ret =
- csr1212_attach_keyval_to_directory(fi->host->csr.
- rom->root_kv,
- dentry->kv);
- }
-
- if (ret == CSR1212_SUCCESS) {
- ret = hpsb_update_config_rom_image(fi->host);
-
- if (ret >= 0 && copy_to_user(int2ptr(req->req.recvb),
- &dr, sizeof(dr))) {
- ret = -ENOMEM;
- }
- }
- }
- kfree(cache->filled_head);
- CSR1212_FREE(cache);
-
- if (ret >= 0) {
- /* we have to free the request, because we queue no response,
- * and therefore nobody will free it */
- free_pending_request(req);
- return 0;
- } else {
- for (dentry =
- fi->csr1212_dirs[dr]->value.directory.dentries_head;
- dentry; dentry = dentry->next) {
- csr1212_detach_keyval_from_directory(fi->host->csr.rom->
- root_kv,
- dentry->kv);
- }
- csr1212_release_keyval(fi->csr1212_dirs[dr]);
- fi->csr1212_dirs[dr] = NULL;
- return ret;
- }
-}
-
-static int state_connected(struct file_info *fi, struct pending_request *req)
-{
- int node = req->req.address >> 48;
-
- req->req.error = RAW1394_ERROR_NONE;
-
- switch (req->req.type) {
-
- case RAW1394_REQ_ECHO:
- queue_complete_req(req);
- return 0;
-
- case RAW1394_REQ_ARM_REGISTER:
- return arm_register(fi, req);
-
- case RAW1394_REQ_ARM_UNREGISTER:
- return arm_unregister(fi, req);
-
- case RAW1394_REQ_ARM_SET_BUF:
- return arm_set_buf(fi, req);
-
- case RAW1394_REQ_ARM_GET_BUF:
- return arm_get_buf(fi, req);
-
- case RAW1394_REQ_RESET_NOTIFY:
- return reset_notification(fi, req);
-
- case RAW1394_REQ_ISO_SEND:
- case RAW1394_REQ_ISO_LISTEN:
- printk(KERN_DEBUG "raw1394: old iso ABI has been removed\n");
- req->req.error = RAW1394_ERROR_COMPAT;
- req->req.misc = RAW1394_KERNELAPI_VERSION;
- queue_complete_req(req);
- return 0;
-
- case RAW1394_REQ_FCP_LISTEN:
- handle_fcp_listen(fi, req);
- return 0;
-
- case RAW1394_REQ_RESET_BUS:
- if (req->req.misc == RAW1394_LONG_RESET) {
- DBGMSG("busreset called (type: LONG)");
- hpsb_reset_bus(fi->host, LONG_RESET);
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
- return 0;
- }
- if (req->req.misc == RAW1394_SHORT_RESET) {
- DBGMSG("busreset called (type: SHORT)");
- hpsb_reset_bus(fi->host, SHORT_RESET);
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
- return 0;
- }
- /* error EINVAL (22) invalid argument */
- return (-EINVAL);
- case RAW1394_REQ_GET_ROM:
- return get_config_rom(fi, req);
-
- case RAW1394_REQ_UPDATE_ROM:
- return update_config_rom(fi, req);
-
- case RAW1394_REQ_MODIFY_ROM:
- return modify_config_rom(fi, req);
- }
-
- if (req->req.generation != get_hpsb_generation(fi->host)) {
- req->req.error = RAW1394_ERROR_GENERATION;
- req->req.generation = get_hpsb_generation(fi->host);
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- switch (req->req.type) {
- case RAW1394_REQ_PHYPACKET:
- return write_phypacket(fi, req);
- case RAW1394_REQ_ASYNC_SEND:
- return handle_async_send(fi, req);
- }
-
- if (req->req.length == 0) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- queue_complete_req(req);
- return 0;
- }
-
- return handle_async_request(fi, req, node);
-}
-
-static ssize_t raw1394_write(struct file *file, const char __user * buffer,
- size_t count, loff_t * offset_is_ignored)
-{
- struct file_info *fi = file->private_data;
- struct pending_request *req;
- ssize_t retval = -EBADFD;
-
-#ifdef CONFIG_COMPAT
- if (count == sizeof(struct compat_raw1394_req) &&
- sizeof(struct compat_raw1394_req) !=
- sizeof(struct raw1394_request)) {
- buffer = raw1394_compat_write(buffer);
- if (IS_ERR((__force void *)buffer))
- return PTR_ERR((__force void *)buffer);
- } else
-#endif
- if (count != sizeof(struct raw1394_request)) {
- return -EINVAL;
- }
-
- req = alloc_pending_request();
- if (req == NULL) {
- return -ENOMEM;
- }
- req->file_info = fi;
-
- if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) {
- free_pending_request(req);
- return -EFAULT;
- }
-
- if (!mutex_trylock(&fi->state_mutex)) {
- free_pending_request(req);
- return -EAGAIN;
- }
-
- switch (fi->state) {
- case opened:
- retval = state_opened(fi, req);
- break;
-
- case initialized:
- retval = state_initialized(fi, req);
- break;
-
- case connected:
- retval = state_connected(fi, req);
- break;
- }
-
- mutex_unlock(&fi->state_mutex);
-
- if (retval < 0) {
- free_pending_request(req);
- } else {
- BUG_ON(retval);
- retval = count;
- }
-
- return retval;
-}
-
-/* rawiso operations */
-
-/* check if any RAW1394_REQ_RAWISO_ACTIVITY event is already in the
- * completion queue (reqlists_lock must be taken) */
-static inline int __rawiso_event_in_queue(struct file_info *fi)
-{
- struct pending_request *req;
-
- list_for_each_entry(req, &fi->req_complete, list)
- if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY)
- return 1;
-
- return 0;
-}
-
-/* put a RAWISO_ACTIVITY event in the queue, if one isn't there already */
-static void queue_rawiso_event(struct file_info *fi)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
-
- /* only one ISO activity event may be in the queue */
- if (!__rawiso_event_in_queue(fi)) {
- struct pending_request *req =
- __alloc_pending_request(GFP_ATOMIC);
-
- if (req) {
- req->file_info = fi;
- req->req.type = RAW1394_REQ_RAWISO_ACTIVITY;
- req->req.generation = get_hpsb_generation(fi->host);
- __queue_complete_req(req);
- } else {
- /* on allocation failure, signal an overflow */
- if (fi->iso_handle) {
- atomic_inc(&fi->iso_handle->overflows);
- }
- }
- }
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-}
-
-static void rawiso_activity_cb(struct hpsb_iso *iso)
-{
- unsigned long flags;
- struct host_info *hi;
- struct file_info *fi;
-
- spin_lock_irqsave(&host_info_lock, flags);
- hi = find_host_info(iso->host);
-
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- if (fi->iso_handle == iso)
- queue_rawiso_event(fi);
- }
- }
-
- spin_unlock_irqrestore(&host_info_lock, flags);
-}
-
-/* helper function - gather all the kernel iso status bits for returning to user-space */
-static void raw1394_iso_fill_status(struct hpsb_iso *iso,
- struct raw1394_iso_status *stat)
-{
- int overflows = atomic_read(&iso->overflows);
- int skips = atomic_read(&iso->skips);
-
- stat->config.data_buf_size = iso->buf_size;
- stat->config.buf_packets = iso->buf_packets;
- stat->config.channel = iso->channel;
- stat->config.speed = iso->speed;
- stat->config.irq_interval = iso->irq_interval;
- stat->n_packets = hpsb_iso_n_ready(iso);
- stat->overflows = ((skips & 0xFFFF) << 16) | ((overflows & 0xFFFF));
- stat->xmit_cycle = iso->xmit_cycle;
-}
-
-static int raw1394_iso_xmit_init(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_iso_status stat;
-
- if (!fi->host)
- return -EINVAL;
-
- if (copy_from_user(&stat, uaddr, sizeof(stat)))
- return -EFAULT;
-
- fi->iso_handle = hpsb_iso_xmit_init(fi->host,
- stat.config.data_buf_size,
- stat.config.buf_packets,
- stat.config.channel,
- stat.config.speed,
- stat.config.irq_interval,
- rawiso_activity_cb);
- if (!fi->iso_handle)
- return -ENOMEM;
-
- fi->iso_state = RAW1394_ISO_XMIT;
-
- raw1394_iso_fill_status(fi->iso_handle, &stat);
- if (copy_to_user(uaddr, &stat, sizeof(stat)))
- return -EFAULT;
-
- /* queue an event to get things started */
- rawiso_activity_cb(fi->iso_handle);
-
- return 0;
-}
-
-static int raw1394_iso_recv_init(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_iso_status stat;
-
- if (!fi->host)
- return -EINVAL;
-
- if (copy_from_user(&stat, uaddr, sizeof(stat)))
- return -EFAULT;
-
- fi->iso_handle = hpsb_iso_recv_init(fi->host,
- stat.config.data_buf_size,
- stat.config.buf_packets,
- stat.config.channel,
- stat.config.dma_mode,
- stat.config.irq_interval,
- rawiso_activity_cb);
- if (!fi->iso_handle)
- return -ENOMEM;
-
- fi->iso_state = RAW1394_ISO_RECV;
-
- raw1394_iso_fill_status(fi->iso_handle, &stat);
- if (copy_to_user(uaddr, &stat, sizeof(stat)))
- return -EFAULT;
- return 0;
-}
-
-static int raw1394_iso_get_status(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_iso_status stat;
- struct hpsb_iso *iso = fi->iso_handle;
-
- raw1394_iso_fill_status(fi->iso_handle, &stat);
- if (copy_to_user(uaddr, &stat, sizeof(stat)))
- return -EFAULT;
-
- /* reset overflow counter */
- atomic_set(&iso->overflows, 0);
- /* reset skip counter */
- atomic_set(&iso->skips, 0);
-
- return 0;
-}
-
-/* copy N packet_infos out of the ringbuffer into user-supplied array */
-static int raw1394_iso_recv_packets(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_iso_packets upackets;
- unsigned int packet = fi->iso_handle->first_packet;
- int i;
-
- if (copy_from_user(&upackets, uaddr, sizeof(upackets)))
- return -EFAULT;
-
- if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle))
- return -EINVAL;
-
- /* ensure user-supplied buffer is accessible and big enough */
- if (!access_ok(VERIFY_WRITE, upackets.infos,
- upackets.n_packets *
- sizeof(struct raw1394_iso_packet_info)))
- return -EFAULT;
-
- /* copy the packet_infos out */
- for (i = 0; i < upackets.n_packets; i++) {
- if (__copy_to_user(&upackets.infos[i],
- &fi->iso_handle->infos[packet],
- sizeof(struct raw1394_iso_packet_info)))
- return -EFAULT;
-
- packet = (packet + 1) % fi->iso_handle->buf_packets;
- }
-
- return 0;
-}
-
-/* copy N packet_infos from user to ringbuffer, and queue them for transmission */
-static int raw1394_iso_send_packets(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_iso_packets upackets;
- int i, rv;
-
- if (copy_from_user(&upackets, uaddr, sizeof(upackets)))
- return -EFAULT;
-
- if (upackets.n_packets >= fi->iso_handle->buf_packets)
- return -EINVAL;
-
- if (upackets.n_packets >= hpsb_iso_n_ready(fi->iso_handle))
- return -EAGAIN;
-
- /* ensure user-supplied buffer is accessible and big enough */
- if (!access_ok(VERIFY_READ, upackets.infos,
- upackets.n_packets *
- sizeof(struct raw1394_iso_packet_info)))
- return -EFAULT;
-
- /* copy the infos structs in and queue the packets */
- for (i = 0; i < upackets.n_packets; i++) {
- struct raw1394_iso_packet_info info;
-
- if (__copy_from_user(&info, &upackets.infos[i],
- sizeof(struct raw1394_iso_packet_info)))
- return -EFAULT;
-
- rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset,
- info.len, info.tag, info.sy);
- if (rv)
- return rv;
- }
-
- return 0;
-}
-
-static void raw1394_iso_shutdown(struct file_info *fi)
-{
- if (fi->iso_handle)
- hpsb_iso_shutdown(fi->iso_handle);
-
- fi->iso_handle = NULL;
- fi->iso_state = RAW1394_ISO_INACTIVE;
-}
-
-static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_cycle_timer ct;
- int err;
-
- err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
- if (!err)
- if (copy_to_user(uaddr, &ct, sizeof(ct)))
- err = -EFAULT;
- return err;
-}
-
-/* mmap the rawiso xmit/recv buffer */
-static int raw1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct file_info *fi = file->private_data;
- int ret;
-
- if (!mutex_trylock(&fi->state_mutex))
- return -EAGAIN;
-
- if (fi->iso_state == RAW1394_ISO_INACTIVE)
- ret = -EINVAL;
- else
- ret = dma_region_mmap(&fi->iso_handle->data_buf, file, vma);
-
- mutex_unlock(&fi->state_mutex);
-
- return ret;
-}
-
-static long raw1394_ioctl_inactive(struct file_info *fi, unsigned int cmd,
- void __user *argp)
-{
- switch (cmd) {
- case RAW1394_IOC_ISO_XMIT_INIT:
- return raw1394_iso_xmit_init(fi, argp);
- case RAW1394_IOC_ISO_RECV_INIT:
- return raw1394_iso_recv_init(fi, argp);
- default:
- return -EINVAL;
- }
-}
-
-static long raw1394_ioctl_recv(struct file_info *fi, unsigned int cmd,
- unsigned long arg)
-{
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
- case RAW1394_IOC_ISO_RECV_START:{
- int args[3];
-
- if (copy_from_user(&args[0], argp, sizeof(args)))
- return -EFAULT;
- return hpsb_iso_recv_start(fi->iso_handle,
- args[0], args[1], args[2]);
- }
- case RAW1394_IOC_ISO_XMIT_RECV_STOP:
- hpsb_iso_stop(fi->iso_handle);
- return 0;
- case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
- return hpsb_iso_recv_listen_channel(fi->iso_handle, arg);
- case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
- return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg);
- case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:{
- u64 mask;
-
- if (copy_from_user(&mask, argp, sizeof(mask)))
- return -EFAULT;
- return hpsb_iso_recv_set_channel_mask(fi->iso_handle,
- mask);
- }
- case RAW1394_IOC_ISO_GET_STATUS:
- return raw1394_iso_get_status(fi, argp);
- case RAW1394_IOC_ISO_RECV_PACKETS:
- return raw1394_iso_recv_packets(fi, argp);
- case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
- return hpsb_iso_recv_release_packets(fi->iso_handle, arg);
- case RAW1394_IOC_ISO_RECV_FLUSH:
- return hpsb_iso_recv_flush(fi->iso_handle);
- case RAW1394_IOC_ISO_SHUTDOWN:
- raw1394_iso_shutdown(fi);
- return 0;
- case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
- queue_rawiso_event(fi);
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-static long raw1394_ioctl_xmit(struct file_info *fi, unsigned int cmd,
- void __user *argp)
-{
- switch (cmd) {
- case RAW1394_IOC_ISO_XMIT_START:{
- int args[2];
-
- if (copy_from_user(&args[0], argp, sizeof(args)))
- return -EFAULT;
- return hpsb_iso_xmit_start(fi->iso_handle,
- args[0], args[1]);
- }
- case RAW1394_IOC_ISO_XMIT_SYNC:
- return hpsb_iso_xmit_sync(fi->iso_handle);
- case RAW1394_IOC_ISO_XMIT_RECV_STOP:
- hpsb_iso_stop(fi->iso_handle);
- return 0;
- case RAW1394_IOC_ISO_GET_STATUS:
- return raw1394_iso_get_status(fi, argp);
- case RAW1394_IOC_ISO_XMIT_PACKETS:
- return raw1394_iso_send_packets(fi, argp);
- case RAW1394_IOC_ISO_SHUTDOWN:
- raw1394_iso_shutdown(fi);
- return 0;
- case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
- queue_rawiso_event(fi);
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-/* ioctl is only used for rawiso operations */
-static long raw1394_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct file_info *fi = file->private_data;
- void __user *argp = (void __user *)arg;
- long ret;
-
- /* state-independent commands */
- switch(cmd) {
- case RAW1394_IOC_GET_CYCLE_TIMER:
- return raw1394_read_cycle_timer(fi, argp);
- default:
- break;
- }
-
- if (!mutex_trylock(&fi->state_mutex))
- return -EAGAIN;
-
- switch (fi->iso_state) {
- case RAW1394_ISO_INACTIVE:
- ret = raw1394_ioctl_inactive(fi, cmd, argp);
- break;
- case RAW1394_ISO_RECV:
- ret = raw1394_ioctl_recv(fi, cmd, arg);
- break;
- case RAW1394_ISO_XMIT:
- ret = raw1394_ioctl_xmit(fi, cmd, argp);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- mutex_unlock(&fi->state_mutex);
-
- return ret;
-}
-
-#ifdef CONFIG_COMPAT
-struct raw1394_iso_packets32 {
- __u32 n_packets;
- compat_uptr_t infos;
-} __attribute__((packed));
-
-struct raw1394_cycle_timer32 {
- __u32 cycle_timer;
- __u64 local_time;
-}
-#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
-__attribute__((packed))
-#endif
-;
-
-#define RAW1394_IOC_ISO_RECV_PACKETS32 \
- _IOW ('#', 0x25, struct raw1394_iso_packets32)
-#define RAW1394_IOC_ISO_XMIT_PACKETS32 \
- _IOW ('#', 0x27, struct raw1394_iso_packets32)
-#define RAW1394_IOC_GET_CYCLE_TIMER32 \
- _IOR ('#', 0x30, struct raw1394_cycle_timer32)
-
-static long raw1394_iso_xmit_recv_packets32(struct file *file, unsigned int cmd,
- struct raw1394_iso_packets32 __user *arg)
-{
- compat_uptr_t infos32;
- void __user *infos;
- long err = -EFAULT;
- struct raw1394_iso_packets __user *dst = compat_alloc_user_space(sizeof(struct raw1394_iso_packets));
-
- if (!copy_in_user(&dst->n_packets, &arg->n_packets, sizeof arg->n_packets) &&
- !copy_from_user(&infos32, &arg->infos, sizeof infos32)) {
- infos = compat_ptr(infos32);
- if (!copy_to_user(&dst->infos, &infos, sizeof infos))
- err = raw1394_ioctl(file, cmd, (unsigned long)dst);
- }
- return err;
-}
-
-static long raw1394_read_cycle_timer32(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_cycle_timer32 ct;
- int err;
-
- err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
- if (!err)
- if (copy_to_user(uaddr, &ct, sizeof(ct)))
- err = -EFAULT;
- return err;
-}
-
-static long raw1394_compat_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct file_info *fi = file->private_data;
- void __user *argp = (void __user *)arg;
- long err;
-
- switch (cmd) {
- /* These requests have same format as long as 'int' has same size. */
- case RAW1394_IOC_ISO_RECV_INIT:
- case RAW1394_IOC_ISO_RECV_START:
- case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
- case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
- case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:
- case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
- case RAW1394_IOC_ISO_RECV_FLUSH:
- case RAW1394_IOC_ISO_XMIT_RECV_STOP:
- case RAW1394_IOC_ISO_XMIT_INIT:
- case RAW1394_IOC_ISO_XMIT_START:
- case RAW1394_IOC_ISO_XMIT_SYNC:
- case RAW1394_IOC_ISO_GET_STATUS:
- case RAW1394_IOC_ISO_SHUTDOWN:
- case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
- err = raw1394_ioctl(file, cmd, arg);
- break;
- /* These request have different format. */
- case RAW1394_IOC_ISO_RECV_PACKETS32:
- err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_RECV_PACKETS, argp);
- break;
- case RAW1394_IOC_ISO_XMIT_PACKETS32:
- err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_XMIT_PACKETS, argp);
- break;
- case RAW1394_IOC_GET_CYCLE_TIMER32:
- err = raw1394_read_cycle_timer32(fi, argp);
- break;
- default:
- err = -EINVAL;
- break;
- }
-
- return err;
-}
-#endif
-
-static unsigned int raw1394_poll(struct file *file, poll_table * pt)
-{
- struct file_info *fi = file->private_data;
- unsigned int mask = POLLOUT | POLLWRNORM;
- unsigned long flags;
-
- poll_wait(file, &fi->wait_complete, pt);
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- if (!list_empty(&fi->req_complete)) {
- mask |= POLLIN | POLLRDNORM;
- }
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
- return mask;
-}
-
-static int raw1394_open(struct inode *inode, struct file *file)
-{
- struct file_info *fi;
-
- fi = kzalloc(sizeof(*fi), GFP_KERNEL);
- if (!fi)
- return -ENOMEM;
-
- fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */
-
- INIT_LIST_HEAD(&fi->list);
- mutex_init(&fi->state_mutex);
- fi->state = opened;
- INIT_LIST_HEAD(&fi->req_pending);
- INIT_LIST_HEAD(&fi->req_complete);
- spin_lock_init(&fi->reqlists_lock);
- init_waitqueue_head(&fi->wait_complete);
- INIT_LIST_HEAD(&fi->addr_list);
-
- file->private_data = fi;
-
- return nonseekable_open(inode, file);
-}
-
-static int raw1394_release(struct inode *inode, struct file *file)
-{
- struct file_info *fi = file->private_data;
- struct list_head *lh;
- struct pending_request *req;
- int i, fail;
- int retval = 0;
- struct list_head *entry;
- struct arm_addr *addr = NULL;
- struct host_info *hi;
- struct file_info *fi_hlp = NULL;
- struct arm_addr *arm_addr = NULL;
- int another_host;
- int csr_mod = 0;
- unsigned long flags;
-
- if (fi->iso_state != RAW1394_ISO_INACTIVE)
- raw1394_iso_shutdown(fi);
-
- spin_lock_irqsave(&host_info_lock, flags);
-
- fail = 0;
- /* set address-entries invalid */
-
- while (!list_empty(&fi->addr_list)) {
- another_host = 0;
- lh = fi->addr_list.next;
- addr = list_entry(lh, struct arm_addr, addr_list);
- /* another host with valid address-entry containing
- same addressrange? */
- list_for_each_entry(hi, &host_info_list, list) {
- if (hi->host != fi->host) {
- list_for_each_entry(fi_hlp, &hi->file_info_list,
- list) {
- entry = fi_hlp->addr_list.next;
- while (entry != &(fi_hlp->addr_list)) {
- arm_addr = list_entry(entry, struct
- arm_addr,
- addr_list);
- if (arm_addr->start ==
- addr->start) {
- DBGMSG
- ("raw1394_release: "
- "another host ownes "
- "same addressrange");
- another_host = 1;
- break;
- }
- entry = entry->next;
- }
- if (another_host) {
- break;
- }
- }
- }
- }
- if (!another_host) {
- DBGMSG("raw1394_release: call hpsb_arm_unregister");
- retval =
- hpsb_unregister_addrspace(&raw1394_highlevel,
- fi->host, addr->start);
- if (!retval) {
- ++fail;
- printk(KERN_ERR
- "raw1394_release arm_Unregister failed\n");
- }
- }
- DBGMSG("raw1394_release: delete addr_entry from list");
- list_del(&addr->addr_list);
- vfree(addr->addr_space_buffer);
- kfree(addr);
- } /* while */
- spin_unlock_irqrestore(&host_info_lock, flags);
- if (fail > 0) {
- printk(KERN_ERR "raw1394: during addr_list-release "
- "error(s) occurred \n");
- }
-
- for (;;) {
- /* This locked section guarantees that neither
- * complete nor pending requests exist once i!=0 */
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- while ((req = __next_complete_req(fi)))
- free_pending_request(req);
-
- i = list_empty(&fi->req_pending);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
- if (i)
- break;
- /*
- * Sleep until more requests can be freed.
- *
- * NB: We call the macro wait_event() with a condition argument
- * with side effect. This is only possible because the side
- * effect does not occur until the condition became true, and
- * wait_event() won't evaluate the condition again after that.
- */
- wait_event(fi->wait_complete, (req = next_complete_req(fi)));
- free_pending_request(req);
- }
-
- /* Remove any sub-trees left by user space programs */
- for (i = 0; i < RAW1394_MAX_USER_CSR_DIRS; i++) {
- struct csr1212_dentry *dentry;
- if (!fi->csr1212_dirs[i])
- continue;
- for (dentry =
- fi->csr1212_dirs[i]->value.directory.dentries_head; dentry;
- dentry = dentry->next) {
- csr1212_detach_keyval_from_directory(fi->host->csr.rom->
- root_kv,
- dentry->kv);
- }
- csr1212_release_keyval(fi->csr1212_dirs[i]);
- fi->csr1212_dirs[i] = NULL;
- csr_mod = 1;
- }
-
- if ((csr_mod || fi->cfgrom_upd)
- && hpsb_update_config_rom_image(fi->host) < 0)
- HPSB_ERR
- ("Failed to generate Configuration ROM image for host %d",
- fi->host->id);
-
- if (fi->state == connected) {
- spin_lock_irqsave(&host_info_lock, flags);
- list_del(&fi->list);
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- put_device(&fi->host->device);
- }
-
- spin_lock_irqsave(&host_info_lock, flags);
- if (fi->host)
- module_put(fi->host->driver->owner);
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- kfree(fi);
-
- return 0;
-}
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id raw1394_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = AVC_SW_VERSION_ENTRY & 0xffffff},
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = CAMERA_SW_VERSION_ENTRY & 0xffffff},
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff},
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff},
- {}
-};
-
-MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver raw1394_driver = {
- .name = "raw1394",
-};
-
-/******************************************************************************/
-
-static struct hpsb_highlevel raw1394_highlevel = {
- .name = RAW1394_DEVICE_NAME,
- .add_host = add_host,
- .remove_host = remove_host,
- .host_reset = host_reset,
- .fcp_request = fcp_request,
-};
-
-static struct cdev raw1394_cdev;
-static const struct file_operations raw1394_fops = {
- .owner = THIS_MODULE,
- .read = raw1394_read,
- .write = raw1394_write,
- .mmap = raw1394_mmap,
- .unlocked_ioctl = raw1394_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = raw1394_compat_ioctl,
-#endif
- .poll = raw1394_poll,
- .open = raw1394_open,
- .release = raw1394_release,
- .llseek = no_llseek,
-};
-
-static int __init init_raw1394(void)
-{
- int ret = 0;
-
- hpsb_register_highlevel(&raw1394_highlevel);
-
- if (IS_ERR
- (device_create(hpsb_protocol_class, NULL,
- MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_RAW1394 * 16),
- NULL, RAW1394_DEVICE_NAME))) {
- ret = -EFAULT;
- goto out_unreg;
- }
-
- cdev_init(&raw1394_cdev, &raw1394_fops);
- raw1394_cdev.owner = THIS_MODULE;
- ret = cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1);
- if (ret) {
- HPSB_ERR("raw1394 failed to register minor device block");
- goto out_dev;
- }
-
- HPSB_INFO("raw1394: /dev/%s device initialized", RAW1394_DEVICE_NAME);
-
- ret = hpsb_register_protocol(&raw1394_driver);
- if (ret) {
- HPSB_ERR("raw1394: failed to register protocol");
- cdev_del(&raw1394_cdev);
- goto out_dev;
- }
-
- goto out;
-
- out_dev:
- device_destroy(hpsb_protocol_class,
- MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_RAW1394 * 16));
- out_unreg:
- hpsb_unregister_highlevel(&raw1394_highlevel);
- out:
- return ret;
-}
-
-static void __exit cleanup_raw1394(void)
-{
- device_destroy(hpsb_protocol_class,
- MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_RAW1394 * 16));
- cdev_del(&raw1394_cdev);
- hpsb_unregister_highlevel(&raw1394_highlevel);
- hpsb_unregister_protocol(&raw1394_driver);
-}
-
-module_init(init_raw1394);
-module_exit(cleanup_raw1394);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h
deleted file mode 100644
index 963ac20373d2..000000000000
--- a/drivers/ieee1394/raw1394.h
+++ /dev/null
@@ -1,191 +0,0 @@
-#ifndef IEEE1394_RAW1394_H
-#define IEEE1394_RAW1394_H
-
-/* header for the raw1394 API that is exported to user-space */
-
-#define RAW1394_KERNELAPI_VERSION 4
-
-/* state: opened */
-#define RAW1394_REQ_INITIALIZE 1
-
-/* state: initialized */
-#define RAW1394_REQ_LIST_CARDS 2
-#define RAW1394_REQ_SET_CARD 3
-
-/* state: connected */
-#define RAW1394_REQ_ASYNC_READ 100
-#define RAW1394_REQ_ASYNC_WRITE 101
-#define RAW1394_REQ_LOCK 102
-#define RAW1394_REQ_LOCK64 103
-#define RAW1394_REQ_ISO_SEND 104 /* removed ABI, now a no-op */
-#define RAW1394_REQ_ASYNC_SEND 105
-#define RAW1394_REQ_ASYNC_STREAM 106
-
-#define RAW1394_REQ_ISO_LISTEN 200 /* removed ABI, now a no-op */
-#define RAW1394_REQ_FCP_LISTEN 201
-#define RAW1394_REQ_RESET_BUS 202
-#define RAW1394_REQ_GET_ROM 203
-#define RAW1394_REQ_UPDATE_ROM 204
-#define RAW1394_REQ_ECHO 205
-#define RAW1394_REQ_MODIFY_ROM 206
-
-#define RAW1394_REQ_ARM_REGISTER 300
-#define RAW1394_REQ_ARM_UNREGISTER 301
-#define RAW1394_REQ_ARM_SET_BUF 302
-#define RAW1394_REQ_ARM_GET_BUF 303
-
-#define RAW1394_REQ_RESET_NOTIFY 400
-
-#define RAW1394_REQ_PHYPACKET 500
-
-/* kernel to user */
-#define RAW1394_REQ_BUS_RESET 10000
-#define RAW1394_REQ_ISO_RECEIVE 10001
-#define RAW1394_REQ_FCP_REQUEST 10002
-#define RAW1394_REQ_ARM 10003
-#define RAW1394_REQ_RAWISO_ACTIVITY 10004
-
-/* error codes */
-#define RAW1394_ERROR_NONE 0
-#define RAW1394_ERROR_COMPAT (-1001)
-#define RAW1394_ERROR_STATE_ORDER (-1002)
-#define RAW1394_ERROR_GENERATION (-1003)
-#define RAW1394_ERROR_INVALID_ARG (-1004)
-#define RAW1394_ERROR_MEMFAULT (-1005)
-#define RAW1394_ERROR_ALREADY (-1006)
-
-#define RAW1394_ERROR_EXCESSIVE (-1020)
-#define RAW1394_ERROR_UNTIDY_LEN (-1021)
-
-#define RAW1394_ERROR_SEND_ERROR (-1100)
-#define RAW1394_ERROR_ABORTED (-1101)
-#define RAW1394_ERROR_TIMEOUT (-1102)
-
-/* arm_codes */
-#define ARM_READ 1
-#define ARM_WRITE 2
-#define ARM_LOCK 4
-
-#define RAW1394_LONG_RESET 0
-#define RAW1394_SHORT_RESET 1
-
-/* busresetnotify ... */
-#define RAW1394_NOTIFY_OFF 0
-#define RAW1394_NOTIFY_ON 1
-
-#include <asm/types.h>
-
-struct raw1394_request {
- __u32 type;
- __s32 error;
- __u32 misc;
-
- __u32 generation;
- __u32 length;
-
- __u64 address;
-
- __u64 tag;
-
- __u64 sendb;
- __u64 recvb;
-};
-
-struct raw1394_khost_list {
- __u32 nodes;
- __u8 name[32];
-};
-
-typedef struct arm_request {
- __u16 destination_nodeid;
- __u16 source_nodeid;
- __u64 destination_offset;
- __u8 tlabel;
- __u8 tcode;
- __u8 extended_transaction_code;
- __u32 generation;
- __u16 buffer_length;
- __u8 __user *buffer;
-} *arm_request_t;
-
-typedef struct arm_response {
- __s32 response_code;
- __u16 buffer_length;
- __u8 __user *buffer;
-} *arm_response_t;
-
-typedef struct arm_request_response {
- struct arm_request __user *request;
- struct arm_response __user *response;
-} *arm_request_response_t;
-
-/* rawiso API */
-#include "ieee1394-ioctl.h"
-
-/* per-packet metadata embedded in the ringbuffer */
-/* must be identical to hpsb_iso_packet_info in iso.h! */
-struct raw1394_iso_packet_info {
- __u32 offset;
- __u16 len;
- __u16 cycle; /* recv only */
- __u8 channel; /* recv only */
- __u8 tag;
- __u8 sy;
-};
-
-/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */
-struct raw1394_iso_packets {
- __u32 n_packets;
- struct raw1394_iso_packet_info __user *infos;
-};
-
-struct raw1394_iso_config {
- /* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */
- __u32 data_buf_size;
-
- /* # of packets to buffer */
- __u32 buf_packets;
-
- /* iso channel (set to -1 for multi-channel recv) */
- __s32 channel;
-
- /* xmit only - iso transmission speed */
- __u8 speed;
-
- /* The mode of the dma when receiving iso data. Must be supported by chip */
- __u8 dma_mode;
-
- /* max. latency of buffer, in packets (-1 if you don't care) */
- __s32 irq_interval;
-};
-
-/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */
-struct raw1394_iso_status {
- /* current settings */
- struct raw1394_iso_config config;
-
- /* number of packets waiting to be filled with data (ISO transmission)
- or containing data received (ISO reception) */
- __u32 n_packets;
-
- /* approximate number of packets dropped due to overflow or
- underflow of the packet buffer (a value of zero guarantees
- that no packets have been dropped) */
- __u32 overflows;
-
- /* cycle number at which next packet will be transmitted;
- -1 if not known */
- __s16 xmit_cycle;
-};
-
-/* argument to RAW1394_IOC_GET_CYCLE_TIMER ioctl */
-struct raw1394_cycle_timer {
- /* contents of Isochronous Cycle Timer register,
- as in OHCI 1.1 clause 5.13 (also with non-OHCI hosts) */
- __u32 cycle_timer;
-
- /* local time in microseconds since Epoch,
- simultaneously read with cycle timer */
- __u64 local_time;
-};
-#endif /* IEEE1394_RAW1394_H */
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
deleted file mode 100644
index d6e251a300ce..000000000000
--- a/drivers/ieee1394/sbp2.c
+++ /dev/null
@@ -1,2138 +0,0 @@
-/*
- * sbp2.c - SBP-2 protocol driver for IEEE-1394
- *
- * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.com (JSG)
- *
- * Copyright (C) 2003 Ben Collins <bcollins@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * Brief Description:
- *
- * This driver implements the Serial Bus Protocol 2 (SBP-2) over IEEE-1394
- * under Linux. The SBP-2 driver is implemented as an IEEE-1394 high-level
- * driver. It also registers as a SCSI lower-level driver in order to accept
- * SCSI commands for transport using SBP-2.
- *
- * You may access any attached SBP-2 (usually storage devices) as regular
- * SCSI devices. E.g. mount /dev/sda1, fdisk, mkfs, etc..
- *
- * See http://www.t10.org/drafts.htm#sbp2 for the final draft of the SBP-2
- * specification and for where to purchase the official standard.
- *
- * TODO:
- * - look into possible improvements of the SCSI error handlers
- * - handle Unit_Characteristics.mgt_ORB_timeout and .ORB_size
- * - handle Logical_Unit_Number.ordered
- * - handle src == 1 in status blocks
- * - reimplement the DMA mapping in absence of physical DMA so that
- * bus_to_virt is no longer required
- * - debug the handling of absent physical DMA
- * - replace CONFIG_IEEE1394_SBP2_PHYS_DMA by automatic detection
- * (this is easy but depends on the previous two TODO items)
- * - make the parameter serialize_io configurable per device
- * - move all requests to fetch agent registers into non-atomic context,
- * replace all usages of sbp2util_node_write_no_wait by true transactions
- * Grep for inline FIXME comments below.
- */
-
-#include <linux/blkdev.h>
-#include <linux/compiler.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/stringify.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/scatterlist.h>
-
-#include <asm/byteorder.h>
-#include <asm/errno.h>
-#include <asm/param.h>
-#include <asm/system.h>
-#include <asm/types.h>
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-#include <asm/io.h> /* for bus_to_virt */
-#endif
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-
-#include "csr1212.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "sbp2.h"
-
-/*
- * Module load parameter definitions
- */
-
-/*
- * Change max_speed on module load if you have a bad IEEE-1394
- * controller that has trouble running 2KB packets at 400mb.
- *
- * NOTE: On certain OHCI parts I have seen short packets on async transmit
- * (probably due to PCI latency/throughput issues with the part). You can
- * bump down the speed if you are running into problems.
- */
-static int sbp2_max_speed = IEEE1394_SPEED_MAX;
-module_param_named(max_speed, sbp2_max_speed, int, 0644);
-MODULE_PARM_DESC(max_speed, "Limit data transfer speed (5 <= 3200, "
- "4 <= 1600, 3 <= 800, 2 <= 400, 1 <= 200, 0 = 100 Mb/s)");
-
-/*
- * Set serialize_io to 0 or N to use dynamically appended lists of command ORBs.
- * This is and always has been buggy in multiple subtle ways. See above TODOs.
- */
-static int sbp2_serialize_io = 1;
-module_param_named(serialize_io, sbp2_serialize_io, bool, 0444);
-MODULE_PARM_DESC(serialize_io, "Serialize requests coming from SCSI drivers "
- "(default = Y, faster but buggy = N)");
-
-/*
- * Adjust max_sectors if you'd like to influence how many sectors each SCSI
- * command can transfer at most. Please note that some older SBP-2 bridge
- * chips are broken for transfers greater or equal to 128KB, therefore
- * max_sectors used to be a safe 255 sectors for many years. We now have a
- * default of 0 here which means that we let the SCSI stack choose a limit.
- *
- * The SBP2_WORKAROUND_128K_MAX_TRANS flag, if set either in the workarounds
- * module parameter or in the sbp2_workarounds_table[], will override the
- * value of max_sectors. We should use sbp2_workarounds_table[] to cover any
- * bridge chip which becomes known to need the 255 sectors limit.
- */
-static int sbp2_max_sectors;
-module_param_named(max_sectors, sbp2_max_sectors, int, 0444);
-MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported "
- "(default = 0 = use SCSI stack's default)");
-
-/*
- * Exclusive login to sbp2 device? In most cases, the sbp2 driver should
- * do an exclusive login, as it's generally unsafe to have two hosts
- * talking to a single sbp2 device at the same time (filesystem coherency,
- * etc.). If you're running an sbp2 device that supports multiple logins,
- * and you're either running read-only filesystems or some sort of special
- * filesystem supporting multiple hosts, e.g. OpenGFS, Oracle Cluster
- * File System, or Lustre, then set exclusive_login to zero.
- *
- * So far only bridges from Oxford Semiconductor are known to support
- * concurrent logins. Depending on firmware, four or two concurrent logins
- * are possible on OXFW911 and newer Oxsemi bridges.
- */
-static int sbp2_exclusive_login = 1;
-module_param_named(exclusive_login, sbp2_exclusive_login, bool, 0644);
-MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
- "(default = Y, use N for concurrent initiators)");
-
-/*
- * If any of the following workarounds is required for your device to work,
- * please submit the kernel messages logged by sbp2 to the linux1394-devel
- * mailing list.
- *
- * - 128kB max transfer
- * Limit transfer size. Necessary for some old bridges.
- *
- * - 36 byte inquiry
- * When scsi_mod probes the device, let the inquiry command look like that
- * from MS Windows.
- *
- * - skip mode page 8
- * Suppress sending of mode_sense for mode page 8 if the device pretends to
- * support the SCSI Primary Block commands instead of Reduced Block Commands.
- *
- * - fix capacity
- * Tell sd_mod to correct the last sector number reported by read_capacity.
- * Avoids access beyond actual disk limits on devices with an off-by-one bug.
- * Don't use this with devices which don't have this bug.
- *
- * - delay inquiry
- * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
- *
- * - power condition
- * Set the power condition field in the START STOP UNIT commands sent by
- * sd_mod on suspend, resume, and shutdown (if manage_start_stop is on).
- * Some disks need this to spin down or to resume properly.
- *
- * - override internal blacklist
- * Instead of adding to the built-in blacklist, use only the workarounds
- * specified in the module load parameter.
- * Useful if a blacklist entry interfered with a non-broken device.
- */
-static int sbp2_default_workarounds;
-module_param_named(workarounds, sbp2_default_workarounds, int, 0644);
-MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
- ", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS)
- ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36)
- ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
- ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
- ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
- ", set power condition in start stop unit = "
- __stringify(SBP2_WORKAROUND_POWER_CONDITION)
- ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
- ", or a combination)");
-
-/*
- * This influences the format of the sysfs attribute
- * /sys/bus/scsi/devices/.../ieee1394_id.
- *
- * The default format is like in older kernels: %016Lx:%d:%d
- * It contains the target's EUI-64, a number given to the logical unit by
- * the ieee1394 driver's nodemgr (starting at 0), and the LUN.
- *
- * The long format is: %016Lx:%06x:%04x
- * It contains the target's EUI-64, the unit directory's directory_ID as per
- * IEEE 1212 clause 7.7.19, and the LUN. This format comes closest to the
- * format of SBP(-3) target port and logical unit identifier as per SAM (SCSI
- * Architecture Model) rev.2 to 4 annex A. Therefore and because it is
- * independent of the implementation of the ieee1394 nodemgr, the longer format
- * is recommended for future use.
- */
-static int sbp2_long_sysfs_ieee1394_id;
-module_param_named(long_ieee1394_id, sbp2_long_sysfs_ieee1394_id, bool, 0644);
-MODULE_PARM_DESC(long_ieee1394_id, "8+3+2 bytes format of ieee1394_id in sysfs "
- "(default = backwards-compatible = N, SAM-conforming = Y)");
-
-
-#define SBP2_INFO(fmt, args...) HPSB_INFO("sbp2: "fmt, ## args)
-#define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)
-
-/*
- * Globals
- */
-static void sbp2scsi_complete_all_commands(struct sbp2_lu *, u32);
-static void sbp2scsi_complete_command(struct sbp2_lu *, u32, struct scsi_cmnd *,
- void (*)(struct scsi_cmnd *));
-static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *);
-static int sbp2_start_device(struct sbp2_lu *);
-static void sbp2_remove_device(struct sbp2_lu *);
-static int sbp2_login_device(struct sbp2_lu *);
-static int sbp2_reconnect_device(struct sbp2_lu *);
-static int sbp2_logout_device(struct sbp2_lu *);
-static void sbp2_host_reset(struct hpsb_host *);
-static int sbp2_handle_status_write(struct hpsb_host *, int, int, quadlet_t *,
- u64, size_t, u16);
-static int sbp2_agent_reset(struct sbp2_lu *, int);
-static void sbp2_parse_unit_directory(struct sbp2_lu *,
- struct unit_directory *);
-static int sbp2_set_busy_timeout(struct sbp2_lu *);
-static int sbp2_max_speed_and_size(struct sbp2_lu *);
-
-
-static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xa, 0xa, 0xa };
-
-static DEFINE_RWLOCK(sbp2_hi_logical_units_lock);
-
-static struct hpsb_highlevel sbp2_highlevel = {
- .name = SBP2_DEVICE_NAME,
- .host_reset = sbp2_host_reset,
-};
-
-static const struct hpsb_address_ops sbp2_ops = {
- .write = sbp2_handle_status_write
-};
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-static int sbp2_handle_physdma_write(struct hpsb_host *, int, int, quadlet_t *,
- u64, size_t, u16);
-static int sbp2_handle_physdma_read(struct hpsb_host *, int, quadlet_t *, u64,
- size_t, u16);
-
-static const struct hpsb_address_ops sbp2_physdma_ops = {
- .read = sbp2_handle_physdma_read,
- .write = sbp2_handle_physdma_write,
-};
-#endif
-
-
-/*
- * Interface to driver core and IEEE 1394 core
- */
-static const struct ieee1394_device_id sbp2_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = SBP2_SW_VERSION_ENTRY & 0xffffff},
- {}
-};
-MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
-
-static int sbp2_probe(struct device *);
-static int sbp2_remove(struct device *);
-static int sbp2_update(struct unit_directory *);
-
-static struct hpsb_protocol_driver sbp2_driver = {
- .name = SBP2_DEVICE_NAME,
- .id_table = sbp2_id_table,
- .update = sbp2_update,
- .driver = {
- .probe = sbp2_probe,
- .remove = sbp2_remove,
- },
-};
-
-
-/*
- * Interface to SCSI core
- */
-static int sbp2scsi_queuecommand(struct scsi_cmnd *,
- void (*)(struct scsi_cmnd *));
-static int sbp2scsi_abort(struct scsi_cmnd *);
-static int sbp2scsi_reset(struct scsi_cmnd *);
-static int sbp2scsi_slave_alloc(struct scsi_device *);
-static int sbp2scsi_slave_configure(struct scsi_device *);
-static void sbp2scsi_slave_destroy(struct scsi_device *);
-static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *,
- struct device_attribute *, char *);
-
-static DEVICE_ATTR(ieee1394_id, S_IRUGO, sbp2_sysfs_ieee1394_id_show, NULL);
-
-static struct device_attribute *sbp2_sysfs_sdev_attrs[] = {
- &dev_attr_ieee1394_id,
- NULL
-};
-
-static struct scsi_host_template sbp2_shost_template = {
- .module = THIS_MODULE,
- .name = "SBP-2 IEEE-1394",
- .proc_name = SBP2_DEVICE_NAME,
- .queuecommand = sbp2scsi_queuecommand,
- .eh_abort_handler = sbp2scsi_abort,
- .eh_device_reset_handler = sbp2scsi_reset,
- .slave_alloc = sbp2scsi_slave_alloc,
- .slave_configure = sbp2scsi_slave_configure,
- .slave_destroy = sbp2scsi_slave_destroy,
- .this_id = -1,
- .sg_tablesize = SG_ALL,
- .use_clustering = ENABLE_CLUSTERING,
- .cmd_per_lun = SBP2_MAX_CMDS,
- .can_queue = SBP2_MAX_CMDS,
- .sdev_attrs = sbp2_sysfs_sdev_attrs,
-};
-
-#define SBP2_ROM_VALUE_WILDCARD ~0 /* match all */
-#define SBP2_ROM_VALUE_MISSING 0xff000000 /* not present in the unit dir. */
-
-/*
- * List of devices with known bugs.
- *
- * The firmware_revision field, masked with 0xffff00, is the best indicator
- * for the type of bridge chip of a device. It yields a few false positives
- * but this did not break correctly behaving devices so far.
- */
-static const struct {
- u32 firmware_revision;
- u32 model;
- unsigned workarounds;
-} sbp2_workarounds_table[] = {
- /* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
- .firmware_revision = 0x002800,
- .model = 0x001010,
- .workarounds = SBP2_WORKAROUND_INQUIRY_36 |
- SBP2_WORKAROUND_MODE_SENSE_8 |
- SBP2_WORKAROUND_POWER_CONDITION,
- },
- /* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
- .firmware_revision = 0x002800,
- .model = 0x000000,
- .workarounds = SBP2_WORKAROUND_POWER_CONDITION,
- },
- /* Initio bridges, actually only needed for some older ones */ {
- .firmware_revision = 0x000200,
- .model = SBP2_ROM_VALUE_WILDCARD,
- .workarounds = SBP2_WORKAROUND_INQUIRY_36,
- },
- /* PL-3507 bridge with Prolific firmware */ {
- .firmware_revision = 0x012800,
- .model = SBP2_ROM_VALUE_WILDCARD,
- .workarounds = SBP2_WORKAROUND_POWER_CONDITION,
- },
- /* Symbios bridge */ {
- .firmware_revision = 0xa0b800,
- .model = SBP2_ROM_VALUE_WILDCARD,
- .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS,
- },
- /* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ {
- .firmware_revision = 0x002600,
- .model = SBP2_ROM_VALUE_WILDCARD,
- .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS,
- },
- /*
- * iPod 2nd generation: needs 128k max transfer size workaround
- * iPod 3rd generation: needs fix capacity workaround
- */
- {
- .firmware_revision = 0x0a2700,
- .model = 0x000000,
- .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS |
- SBP2_WORKAROUND_FIX_CAPACITY,
- },
- /* iPod 4th generation */ {
- .firmware_revision = 0x0a2700,
- .model = 0x000021,
- .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
- },
- /* iPod mini */ {
- .firmware_revision = 0x0a2700,
- .model = 0x000022,
- .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
- },
- /* iPod mini */ {
- .firmware_revision = 0x0a2700,
- .model = 0x000023,
- .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
- },
- /* iPod Photo */ {
- .firmware_revision = 0x0a2700,
- .model = 0x00007e,
- .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
- }
-};
-
-/**************************************
- * General utility functions
- **************************************/
-
-#ifndef __BIG_ENDIAN
-/*
- * Converts a buffer from be32 to cpu byte ordering. Length is in bytes.
- */
-static inline void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
-{
- u32 *temp = buffer;
-
- for (length = (length >> 2); length--; )
- temp[length] = be32_to_cpu(temp[length]);
-}
-
-/*
- * Converts a buffer from cpu to be32 byte ordering. Length is in bytes.
- */
-static inline void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
-{
- u32 *temp = buffer;
-
- for (length = (length >> 2); length--; )
- temp[length] = cpu_to_be32(temp[length]);
-}
-#else /* BIG_ENDIAN */
-/* Why waste the cpu cycles? */
-#define sbp2util_be32_to_cpu_buffer(x,y) do {} while (0)
-#define sbp2util_cpu_to_be32_buffer(x,y) do {} while (0)
-#endif
-
-static DECLARE_WAIT_QUEUE_HEAD(sbp2_access_wq);
-
-/*
- * Waits for completion of an SBP-2 access request.
- * Returns nonzero if timed out or prematurely interrupted.
- */
-static int sbp2util_access_timeout(struct sbp2_lu *lu, int timeout)
-{
- long leftover;
-
- leftover = wait_event_interruptible_timeout(
- sbp2_access_wq, lu->access_complete, timeout);
- lu->access_complete = 0;
- return leftover <= 0;
-}
-
-static void sbp2_free_packet(void *packet)
-{
- hpsb_free_tlabel(packet);
- hpsb_free_packet(packet);
-}
-
-/*
- * This is much like hpsb_node_write(), except it ignores the response
- * subaction and returns immediately. Can be used from atomic context.
- */
-static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
- quadlet_t *buf, size_t len)
-{
- struct hpsb_packet *packet;
-
- packet = hpsb_make_writepacket(ne->host, ne->nodeid, addr, buf, len);
- if (!packet)
- return -ENOMEM;
-
- hpsb_set_packet_complete_task(packet, sbp2_free_packet, packet);
- hpsb_node_fill_packet(ne, packet);
- if (hpsb_send_packet(packet) < 0) {
- sbp2_free_packet(packet);
- return -EIO;
- }
- return 0;
-}
-
-static void sbp2util_notify_fetch_agent(struct sbp2_lu *lu, u64 offset,
- quadlet_t *data, size_t len)
-{
- /* There is a small window after a bus reset within which the node
- * entry's generation is current but the reconnect wasn't completed. */
- if (unlikely(atomic_read(&lu->state) == SBP2LU_STATE_IN_RESET))
- return;
-
- if (hpsb_node_write(lu->ne, lu->command_block_agent_addr + offset,
- data, len))
- SBP2_ERR("sbp2util_notify_fetch_agent failed.");
-
- /* Now accept new SCSI commands, unless a bus reset happended during
- * hpsb_node_write. */
- if (likely(atomic_read(&lu->state) != SBP2LU_STATE_IN_RESET))
- scsi_unblock_requests(lu->shost);
-}
-
-static void sbp2util_write_orb_pointer(struct work_struct *work)
-{
- struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work);
- quadlet_t data[2];
-
- data[0] = ORB_SET_NODE_ID(lu->hi->host->node_id);
- data[1] = lu->last_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
- sbp2util_notify_fetch_agent(lu, SBP2_ORB_POINTER_OFFSET, data, 8);
-}
-
-static void sbp2util_write_doorbell(struct work_struct *work)
-{
- struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work);
-
- sbp2util_notify_fetch_agent(lu, SBP2_DOORBELL_OFFSET, NULL, 4);
-}
-
-static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
-{
- struct sbp2_command_info *cmd;
- struct device *dmadev = lu->hi->host->device.parent;
- int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
-
- for (i = 0; i < orbs; i++) {
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd)
- goto failed_alloc;
-
- cmd->command_orb_dma =
- dma_map_single(dmadev, &cmd->command_orb,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- if (dma_mapping_error(dmadev, cmd->command_orb_dma))
- goto failed_orb;
-
- cmd->sge_dma =
- dma_map_single(dmadev, &cmd->scatter_gather_element,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
- if (dma_mapping_error(dmadev, cmd->sge_dma))
- goto failed_sge;
-
- INIT_LIST_HEAD(&cmd->list);
- list_add_tail(&cmd->list, &lu->cmd_orb_completed);
- }
- return 0;
-
-failed_sge:
- dma_unmap_single(dmadev, cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
-failed_orb:
- kfree(cmd);
-failed_alloc:
- return -ENOMEM;
-}
-
-static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu,
- struct hpsb_host *host)
-{
- struct list_head *lh, *next;
- struct sbp2_command_info *cmd;
- unsigned long flags;
-
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- if (!list_empty(&lu->cmd_orb_completed))
- list_for_each_safe(lh, next, &lu->cmd_orb_completed) {
- cmd = list_entry(lh, struct sbp2_command_info, list);
- dma_unmap_single(host->device.parent,
- cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- dma_unmap_single(host->device.parent, cmd->sge_dma,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
- kfree(cmd);
- }
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
- return;
-}
-
-/*
- * Finds the sbp2_command for a given outstanding command ORB.
- * Only looks at the in-use list.
- */
-static struct sbp2_command_info *sbp2util_find_command_for_orb(
- struct sbp2_lu *lu, dma_addr_t orb)
-{
- struct sbp2_command_info *cmd;
- unsigned long flags;
-
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- if (!list_empty(&lu->cmd_orb_inuse))
- list_for_each_entry(cmd, &lu->cmd_orb_inuse, list)
- if (cmd->command_orb_dma == orb) {
- spin_unlock_irqrestore(
- &lu->cmd_orb_lock, flags);
- return cmd;
- }
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
- return NULL;
-}
-
-/*
- * Finds the sbp2_command for a given outstanding SCpnt.
- * Only looks at the in-use list.
- * Must be called with lu->cmd_orb_lock held.
- */
-static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(
- struct sbp2_lu *lu, void *SCpnt)
-{
- struct sbp2_command_info *cmd;
-
- if (!list_empty(&lu->cmd_orb_inuse))
- list_for_each_entry(cmd, &lu->cmd_orb_inuse, list)
- if (cmd->Current_SCpnt == SCpnt)
- return cmd;
- return NULL;
-}
-
-static struct sbp2_command_info *sbp2util_allocate_command_orb(
- struct sbp2_lu *lu,
- struct scsi_cmnd *Current_SCpnt,
- void (*Current_done)(struct scsi_cmnd *))
-{
- struct list_head *lh;
- struct sbp2_command_info *cmd = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- if (!list_empty(&lu->cmd_orb_completed)) {
- lh = lu->cmd_orb_completed.next;
- list_del(lh);
- cmd = list_entry(lh, struct sbp2_command_info, list);
- cmd->Current_done = Current_done;
- cmd->Current_SCpnt = Current_SCpnt;
- list_add_tail(&cmd->list, &lu->cmd_orb_inuse);
- } else
- SBP2_ERR("%s: no orbs available", __func__);
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
- return cmd;
-}
-
-/*
- * Unmaps the DMAs of a command and moves the command to the completed ORB list.
- * Must be called with lu->cmd_orb_lock held.
- */
-static void sbp2util_mark_command_completed(struct sbp2_lu *lu,
- struct sbp2_command_info *cmd)
-{
- if (scsi_sg_count(cmd->Current_SCpnt))
- dma_unmap_sg(lu->ud->ne->host->device.parent,
- scsi_sglist(cmd->Current_SCpnt),
- scsi_sg_count(cmd->Current_SCpnt),
- cmd->Current_SCpnt->sc_data_direction);
- list_move_tail(&cmd->list, &lu->cmd_orb_completed);
-}
-
-/*
- * Is lu valid? Is the 1394 node still present?
- */
-static inline int sbp2util_node_is_available(struct sbp2_lu *lu)
-{
- return lu && lu->ne && !lu->ne->in_limbo;
-}
-
-/*********************************************
- * IEEE-1394 core driver stack related section
- *********************************************/
-
-static int sbp2_probe(struct device *dev)
-{
- struct unit_directory *ud;
- struct sbp2_lu *lu;
-
- ud = container_of(dev, struct unit_directory, device);
-
- /* Don't probe UD's that have the LUN flag. We'll probe the LUN(s)
- * instead. */
- if (ud->flags & UNIT_DIRECTORY_HAS_LUN_DIRECTORY)
- return -ENODEV;
-
- lu = sbp2_alloc_device(ud);
- if (!lu)
- return -ENOMEM;
-
- sbp2_parse_unit_directory(lu, ud);
- return sbp2_start_device(lu);
-}
-
-static int sbp2_remove(struct device *dev)
-{
- struct unit_directory *ud;
- struct sbp2_lu *lu;
- struct scsi_device *sdev;
-
- ud = container_of(dev, struct unit_directory, device);
- lu = dev_get_drvdata(&ud->device);
- if (!lu)
- return 0;
-
- if (lu->shost) {
- /* Get rid of enqueued commands if there is no chance to
- * send them. */
- if (!sbp2util_node_is_available(lu))
- sbp2scsi_complete_all_commands(lu, DID_NO_CONNECT);
- /* scsi_remove_device() may trigger shutdown functions of SCSI
- * highlevel drivers which would deadlock if blocked. */
- atomic_set(&lu->state, SBP2LU_STATE_IN_SHUTDOWN);
- scsi_unblock_requests(lu->shost);
- }
- sdev = lu->sdev;
- if (sdev) {
- lu->sdev = NULL;
- scsi_remove_device(sdev);
- }
-
- sbp2_logout_device(lu);
- sbp2_remove_device(lu);
-
- return 0;
-}
-
-static int sbp2_update(struct unit_directory *ud)
-{
- struct sbp2_lu *lu = dev_get_drvdata(&ud->device);
-
- if (sbp2_reconnect_device(lu) != 0) {
- /*
- * Reconnect failed. If another bus reset happened,
- * let nodemgr proceed and call sbp2_update again later
- * (or sbp2_remove if this node went away).
- */
- if (!hpsb_node_entry_valid(lu->ne))
- return 0;
- /*
- * Or the target rejected the reconnect because we weren't
- * fast enough. Try a regular login, but first log out
- * just in case of any weirdness.
- */
- sbp2_logout_device(lu);
-
- if (sbp2_login_device(lu) != 0) {
- if (!hpsb_node_entry_valid(lu->ne))
- return 0;
-
- /* Maybe another initiator won the login. */
- SBP2_ERR("Failed to reconnect to sbp2 device!");
- return -EBUSY;
- }
- }
-
- sbp2_set_busy_timeout(lu);
- sbp2_agent_reset(lu, 1);
- sbp2_max_speed_and_size(lu);
-
- /* Complete any pending commands with busy (so they get retried)
- * and remove them from our queue. */
- sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY);
-
- /* Accept new commands unless there was another bus reset in the
- * meantime. */
- if (hpsb_node_entry_valid(lu->ne)) {
- atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
- scsi_unblock_requests(lu->shost);
- }
- return 0;
-}
-
-static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
-{
- struct sbp2_fwhost_info *hi;
- struct Scsi_Host *shost = NULL;
- struct sbp2_lu *lu = NULL;
- unsigned long flags;
-
- lu = kzalloc(sizeof(*lu), GFP_KERNEL);
- if (!lu) {
- SBP2_ERR("failed to create lu");
- goto failed_alloc;
- }
-
- lu->ne = ud->ne;
- lu->ud = ud;
- lu->speed_code = IEEE1394_SPEED_100;
- lu->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
- lu->status_fifo_addr = CSR1212_INVALID_ADDR_SPACE;
- INIT_LIST_HEAD(&lu->cmd_orb_inuse);
- INIT_LIST_HEAD(&lu->cmd_orb_completed);
- INIT_LIST_HEAD(&lu->lu_list);
- spin_lock_init(&lu->cmd_orb_lock);
- atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
- INIT_WORK(&lu->protocol_work, NULL);
-
- dev_set_drvdata(&ud->device, lu);
-
- hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host);
- if (!hi) {
- hi = hpsb_create_hostinfo(&sbp2_highlevel, ud->ne->host,
- sizeof(*hi));
- if (!hi) {
- SBP2_ERR("failed to allocate hostinfo");
- goto failed_alloc;
- }
- hi->host = ud->ne->host;
- INIT_LIST_HEAD(&hi->logical_units);
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
- /* Handle data movement if physical dma is not
- * enabled or not supported on host controller */
- if (!hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host,
- &sbp2_physdma_ops,
- 0x0ULL, 0xfffffffcULL)) {
- SBP2_ERR("failed to register lower 4GB address range");
- goto failed_alloc;
- }
-#endif
- }
-
- if (dma_get_max_seg_size(hi->host->device.parent) > SBP2_MAX_SEG_SIZE)
- BUG_ON(dma_set_max_seg_size(hi->host->device.parent,
- SBP2_MAX_SEG_SIZE));
-
- /* Prevent unloading of the 1394 host */
- if (!try_module_get(hi->host->driver->owner)) {
- SBP2_ERR("failed to get a reference on 1394 host driver");
- goto failed_alloc;
- }
-
- lu->hi = hi;
-
- write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
- list_add_tail(&lu->lu_list, &hi->logical_units);
- write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
- /* Register the status FIFO address range. We could use the same FIFO
- * for targets at different nodes. However we need different FIFOs per
- * target in order to support multi-unit devices.
- * The FIFO is located out of the local host controller's physical range
- * but, if possible, within the posted write area. Status writes will
- * then be performed as unified transactions. This slightly reduces
- * bandwidth usage, and some Prolific based devices seem to require it.
- */
- lu->status_fifo_addr = hpsb_allocate_and_register_addrspace(
- &sbp2_highlevel, ud->ne->host, &sbp2_ops,
- sizeof(struct sbp2_status_block), sizeof(quadlet_t),
- ud->ne->host->low_addr_space, CSR1212_ALL_SPACE_END);
- if (lu->status_fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
- SBP2_ERR("failed to allocate status FIFO address range");
- goto failed_alloc;
- }
-
- shost = scsi_host_alloc(&sbp2_shost_template, sizeof(unsigned long));
- if (!shost) {
- SBP2_ERR("failed to register scsi host");
- goto failed_alloc;
- }
-
- shost->hostdata[0] = (unsigned long)lu;
- shost->max_cmd_len = SBP2_MAX_CDB_SIZE;
-
- if (!scsi_add_host(shost, &ud->device)) {
- lu->shost = shost;
- return lu;
- }
-
- SBP2_ERR("failed to add scsi host");
- scsi_host_put(shost);
-
-failed_alloc:
- sbp2_remove_device(lu);
- return NULL;
-}
-
-static void sbp2_host_reset(struct hpsb_host *host)
-{
- struct sbp2_fwhost_info *hi;
- struct sbp2_lu *lu;
- unsigned long flags;
-
- hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
- if (!hi)
- return;
-
- read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
-
- list_for_each_entry(lu, &hi->logical_units, lu_list)
- if (atomic_cmpxchg(&lu->state,
- SBP2LU_STATE_RUNNING, SBP2LU_STATE_IN_RESET)
- == SBP2LU_STATE_RUNNING)
- scsi_block_requests(lu->shost);
-
- read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-}
-
-static int sbp2_start_device(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- int error;
-
- lu->login_response = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_login_response),
- &lu->login_response_dma, GFP_KERNEL);
- if (!lu->login_response)
- goto alloc_fail;
-
- lu->query_logins_orb = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_query_logins_orb),
- &lu->query_logins_orb_dma, GFP_KERNEL);
- if (!lu->query_logins_orb)
- goto alloc_fail;
-
- lu->query_logins_response = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_query_logins_response),
- &lu->query_logins_response_dma, GFP_KERNEL);
- if (!lu->query_logins_response)
- goto alloc_fail;
-
- lu->reconnect_orb = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_reconnect_orb),
- &lu->reconnect_orb_dma, GFP_KERNEL);
- if (!lu->reconnect_orb)
- goto alloc_fail;
-
- lu->logout_orb = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_logout_orb),
- &lu->logout_orb_dma, GFP_KERNEL);
- if (!lu->logout_orb)
- goto alloc_fail;
-
- lu->login_orb = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_login_orb),
- &lu->login_orb_dma, GFP_KERNEL);
- if (!lu->login_orb)
- goto alloc_fail;
-
- if (sbp2util_create_command_orb_pool(lu))
- goto alloc_fail;
-
- /* Wait a second before trying to log in. Previously logged in
- * initiators need a chance to reconnect. */
- if (msleep_interruptible(1000)) {
- sbp2_remove_device(lu);
- return -EINTR;
- }
-
- if (sbp2_login_device(lu)) {
- sbp2_remove_device(lu);
- return -EBUSY;
- }
-
- sbp2_set_busy_timeout(lu);
- sbp2_agent_reset(lu, 1);
- sbp2_max_speed_and_size(lu);
-
- if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
- ssleep(SBP2_INQUIRY_DELAY);
-
- error = scsi_add_device(lu->shost, 0, lu->ud->id, 0);
- if (error) {
- SBP2_ERR("scsi_add_device failed");
- sbp2_logout_device(lu);
- sbp2_remove_device(lu);
- return error;
- }
-
- return 0;
-
-alloc_fail:
- SBP2_ERR("Could not allocate memory for lu");
- sbp2_remove_device(lu);
- return -ENOMEM;
-}
-
-static void sbp2_remove_device(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi;
- unsigned long flags;
-
- if (!lu)
- return;
- hi = lu->hi;
- if (!hi)
- goto no_hi;
-
- if (lu->shost) {
- scsi_remove_host(lu->shost);
- scsi_host_put(lu->shost);
- }
- flush_scheduled_work();
- sbp2util_remove_command_orb_pool(lu, hi->host);
-
- write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
- list_del(&lu->lu_list);
- write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
- if (lu->login_response)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_login_response),
- lu->login_response,
- lu->login_response_dma);
- if (lu->login_orb)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_login_orb),
- lu->login_orb,
- lu->login_orb_dma);
- if (lu->reconnect_orb)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_reconnect_orb),
- lu->reconnect_orb,
- lu->reconnect_orb_dma);
- if (lu->logout_orb)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_logout_orb),
- lu->logout_orb,
- lu->logout_orb_dma);
- if (lu->query_logins_orb)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_query_logins_orb),
- lu->query_logins_orb,
- lu->query_logins_orb_dma);
- if (lu->query_logins_response)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_query_logins_response),
- lu->query_logins_response,
- lu->query_logins_response_dma);
-
- if (lu->status_fifo_addr != CSR1212_INVALID_ADDR_SPACE)
- hpsb_unregister_addrspace(&sbp2_highlevel, hi->host,
- lu->status_fifo_addr);
-
- dev_set_drvdata(&lu->ud->device, NULL);
-
- module_put(hi->host->driver->owner);
-no_hi:
- kfree(lu);
-}
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-/*
- * Deal with write requests on adapters which do not support physical DMA or
- * have it switched off.
- */
-static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid,
- int destid, quadlet_t *data, u64 addr,
- size_t length, u16 flags)
-{
- memcpy(bus_to_virt((u32) addr), data, length);
- return RCODE_COMPLETE;
-}
-
-/*
- * Deal with read requests on adapters which do not support physical DMA or
- * have it switched off.
- */
-static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid,
- quadlet_t *data, u64 addr, size_t length,
- u16 flags)
-{
- memcpy(data, bus_to_virt((u32) addr), length);
- return RCODE_COMPLETE;
-}
-#endif
-
-/**************************************
- * SBP-2 protocol related section
- **************************************/
-
-static int sbp2_query_logins(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- quadlet_t data[2];
- int max_logins;
- int active_logins;
-
- lu->query_logins_orb->reserved1 = 0x0;
- lu->query_logins_orb->reserved2 = 0x0;
-
- lu->query_logins_orb->query_response_lo = lu->query_logins_response_dma;
- lu->query_logins_orb->query_response_hi =
- ORB_SET_NODE_ID(hi->host->node_id);
- lu->query_logins_orb->lun_misc =
- ORB_SET_FUNCTION(SBP2_QUERY_LOGINS_REQUEST);
- lu->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
- lu->query_logins_orb->lun_misc |= ORB_SET_LUN(lu->lun);
-
- lu->query_logins_orb->reserved_resp_length =
- ORB_SET_QUERY_LOGINS_RESP_LENGTH(
- sizeof(struct sbp2_query_logins_response));
-
- lu->query_logins_orb->status_fifo_hi =
- ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
- lu->query_logins_orb->status_fifo_lo =
- ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
- sbp2util_cpu_to_be32_buffer(lu->query_logins_orb,
- sizeof(struct sbp2_query_logins_orb));
-
- memset(lu->query_logins_response, 0,
- sizeof(struct sbp2_query_logins_response));
-
- data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- data[1] = lu->query_logins_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
-
- hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-
- if (sbp2util_access_timeout(lu, 2*HZ)) {
- SBP2_INFO("Error querying logins to SBP-2 device - timed out");
- return -EIO;
- }
-
- if (lu->status_block.ORB_offset_lo != lu->query_logins_orb_dma) {
- SBP2_INFO("Error querying logins to SBP-2 device - timed out");
- return -EIO;
- }
-
- if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
- SBP2_INFO("Error querying logins to SBP-2 device - failed");
- return -EIO;
- }
-
- sbp2util_cpu_to_be32_buffer(lu->query_logins_response,
- sizeof(struct sbp2_query_logins_response));
-
- max_logins = RESPONSE_GET_MAX_LOGINS(
- lu->query_logins_response->length_max_logins);
- SBP2_INFO("Maximum concurrent logins supported: %d", max_logins);
-
- active_logins = RESPONSE_GET_ACTIVE_LOGINS(
- lu->query_logins_response->length_max_logins);
- SBP2_INFO("Number of active logins: %d", active_logins);
-
- if (active_logins >= max_logins) {
- return -EIO;
- }
-
- return 0;
-}
-
-static int sbp2_login_device(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- quadlet_t data[2];
-
- if (!lu->login_orb)
- return -EIO;
-
- if (!sbp2_exclusive_login && sbp2_query_logins(lu)) {
- SBP2_INFO("Device does not support any more concurrent logins");
- return -EIO;
- }
-
- /* assume no password */
- lu->login_orb->password_hi = 0;
- lu->login_orb->password_lo = 0;
-
- lu->login_orb->login_response_lo = lu->login_response_dma;
- lu->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
- lu->login_orb->lun_misc = ORB_SET_FUNCTION(SBP2_LOGIN_REQUEST);
-
- /* one second reconnect time */
- lu->login_orb->lun_misc |= ORB_SET_RECONNECT(0);
- lu->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(sbp2_exclusive_login);
- lu->login_orb->lun_misc |= ORB_SET_NOTIFY(1);
- lu->login_orb->lun_misc |= ORB_SET_LUN(lu->lun);
-
- lu->login_orb->passwd_resp_lengths =
- ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
-
- lu->login_orb->status_fifo_hi =
- ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
- lu->login_orb->status_fifo_lo =
- ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
- sbp2util_cpu_to_be32_buffer(lu->login_orb,
- sizeof(struct sbp2_login_orb));
-
- memset(lu->login_response, 0, sizeof(struct sbp2_login_response));
-
- data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- data[1] = lu->login_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
-
- hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-
- /* wait up to 20 seconds for login status */
- if (sbp2util_access_timeout(lu, 20*HZ)) {
- SBP2_ERR("Error logging into SBP-2 device - timed out");
- return -EIO;
- }
-
- /* make sure that the returned status matches the login ORB */
- if (lu->status_block.ORB_offset_lo != lu->login_orb_dma) {
- SBP2_ERR("Error logging into SBP-2 device - timed out");
- return -EIO;
- }
-
- if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
- SBP2_ERR("Error logging into SBP-2 device - failed");
- return -EIO;
- }
-
- sbp2util_cpu_to_be32_buffer(lu->login_response,
- sizeof(struct sbp2_login_response));
- lu->command_block_agent_addr =
- ((u64)lu->login_response->command_block_agent_hi) << 32;
- lu->command_block_agent_addr |=
- ((u64)lu->login_response->command_block_agent_lo);
- lu->command_block_agent_addr &= 0x0000ffffffffffffULL;
-
- SBP2_INFO("Logged into SBP-2 device");
- return 0;
-}
-
-static int sbp2_logout_device(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- quadlet_t data[2];
- int error;
-
- lu->logout_orb->reserved1 = 0x0;
- lu->logout_orb->reserved2 = 0x0;
- lu->logout_orb->reserved3 = 0x0;
- lu->logout_orb->reserved4 = 0x0;
-
- lu->logout_orb->login_ID_misc = ORB_SET_FUNCTION(SBP2_LOGOUT_REQUEST);
- lu->logout_orb->login_ID_misc |=
- ORB_SET_LOGIN_ID(lu->login_response->length_login_ID);
- lu->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
-
- lu->logout_orb->reserved5 = 0x0;
- lu->logout_orb->status_fifo_hi =
- ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
- lu->logout_orb->status_fifo_lo =
- ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
- sbp2util_cpu_to_be32_buffer(lu->logout_orb,
- sizeof(struct sbp2_logout_orb));
-
- data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- data[1] = lu->logout_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
-
- error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
- if (error)
- return error;
-
- /* wait up to 1 second for the device to complete logout */
- if (sbp2util_access_timeout(lu, HZ))
- return -EIO;
-
- SBP2_INFO("Logged out of SBP-2 device");
- return 0;
-}
-
-static int sbp2_reconnect_device(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- quadlet_t data[2];
- int error;
-
- lu->reconnect_orb->reserved1 = 0x0;
- lu->reconnect_orb->reserved2 = 0x0;
- lu->reconnect_orb->reserved3 = 0x0;
- lu->reconnect_orb->reserved4 = 0x0;
-
- lu->reconnect_orb->login_ID_misc =
- ORB_SET_FUNCTION(SBP2_RECONNECT_REQUEST);
- lu->reconnect_orb->login_ID_misc |=
- ORB_SET_LOGIN_ID(lu->login_response->length_login_ID);
- lu->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
-
- lu->reconnect_orb->reserved5 = 0x0;
- lu->reconnect_orb->status_fifo_hi =
- ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
- lu->reconnect_orb->status_fifo_lo =
- ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
- sbp2util_cpu_to_be32_buffer(lu->reconnect_orb,
- sizeof(struct sbp2_reconnect_orb));
-
- data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- data[1] = lu->reconnect_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
-
- error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
- if (error)
- return error;
-
- /* wait up to 1 second for reconnect status */
- if (sbp2util_access_timeout(lu, HZ)) {
- SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
- return -EIO;
- }
-
- /* make sure that the returned status matches the reconnect ORB */
- if (lu->status_block.ORB_offset_lo != lu->reconnect_orb_dma) {
- SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
- return -EIO;
- }
-
- if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
- SBP2_ERR("Error reconnecting to SBP-2 device - failed");
- return -EIO;
- }
-
- SBP2_INFO("Reconnected to SBP-2 device");
- return 0;
-}
-
-/*
- * Set the target node's Single Phase Retry limit. Affects the target's retry
- * behaviour if our node is too busy to accept requests.
- */
-static int sbp2_set_busy_timeout(struct sbp2_lu *lu)
-{
- quadlet_t data;
-
- data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);
- if (hpsb_node_write(lu->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4))
- SBP2_ERR("%s error", __func__);
- return 0;
-}
-
-static void sbp2_parse_unit_directory(struct sbp2_lu *lu,
- struct unit_directory *ud)
-{
- struct csr1212_keyval *kv;
- struct csr1212_dentry *dentry;
- u64 management_agent_addr;
- u32 firmware_revision, model;
- unsigned workarounds;
- int i;
-
- management_agent_addr = 0;
- firmware_revision = SBP2_ROM_VALUE_MISSING;
- model = ud->flags & UNIT_DIRECTORY_MODEL_ID ?
- ud->model_id : SBP2_ROM_VALUE_MISSING;
-
- csr1212_for_each_dir_entry(ud->ne->csr, kv, ud->ud_kv, dentry) {
- switch (kv->key.id) {
- case CSR1212_KV_ID_DEPENDENT_INFO:
- if (kv->key.type == CSR1212_KV_TYPE_CSR_OFFSET)
- management_agent_addr =
- CSR1212_REGISTER_SPACE_BASE +
- (kv->value.csr_offset << 2);
-
- else if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE)
- lu->lun = ORB_SET_LUN(kv->value.immediate);
- break;
-
-
- case SBP2_FIRMWARE_REVISION_KEY:
- firmware_revision = kv->value.immediate;
- break;
-
- default:
- /* FIXME: Check for SBP2_UNIT_CHARACTERISTICS_KEY
- * mgt_ORB_timeout and ORB_size, SBP-2 clause 7.4.8. */
-
- /* FIXME: Check for SBP2_DEVICE_TYPE_AND_LUN_KEY.
- * Its "ordered" bit has consequences for command ORB
- * list handling. See SBP-2 clauses 4.6, 7.4.11, 10.2 */
- break;
- }
- }
-
- workarounds = sbp2_default_workarounds;
-
- if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
- for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
- if (sbp2_workarounds_table[i].firmware_revision !=
- SBP2_ROM_VALUE_WILDCARD &&
- sbp2_workarounds_table[i].firmware_revision !=
- (firmware_revision & 0xffff00))
- continue;
- if (sbp2_workarounds_table[i].model !=
- SBP2_ROM_VALUE_WILDCARD &&
- sbp2_workarounds_table[i].model != model)
- continue;
- workarounds |= sbp2_workarounds_table[i].workarounds;
- break;
- }
-
- if (workarounds)
- SBP2_INFO("Workarounds for node " NODE_BUS_FMT ": 0x%x "
- "(firmware_revision 0x%06x, vendor_id 0x%06x,"
- " model_id 0x%06x)",
- NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid),
- workarounds, firmware_revision, ud->vendor_id,
- model);
-
- /* We would need one SCSI host template for each target to adjust
- * max_sectors on the fly, therefore warn only. */
- if (workarounds & SBP2_WORKAROUND_128K_MAX_TRANS &&
- (sbp2_max_sectors * 512) > (128 * 1024))
- SBP2_INFO("Node " NODE_BUS_FMT ": Bridge only supports 128KB "
- "max transfer size. WARNING: Current max_sectors "
- "setting is larger than 128KB (%d sectors)",
- NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid),
- sbp2_max_sectors);
-
- /* If this is a logical unit directory entry, process the parent
- * to get the values. */
- if (ud->flags & UNIT_DIRECTORY_LUN_DIRECTORY) {
- struct unit_directory *parent_ud = container_of(
- ud->device.parent, struct unit_directory, device);
- sbp2_parse_unit_directory(lu, parent_ud);
- } else {
- lu->management_agent_addr = management_agent_addr;
- lu->workarounds = workarounds;
- if (ud->flags & UNIT_DIRECTORY_HAS_LUN)
- lu->lun = ORB_SET_LUN(ud->lun);
- }
-}
-
-#define SBP2_PAYLOAD_TO_BYTES(p) (1 << ((p) + 2))
-
-/*
- * This function is called in order to determine the max speed and packet
- * size we can use in our ORBs. Note, that we (the driver and host) only
- * initiate the transaction. The SBP-2 device actually transfers the data
- * (by reading from the DMA area we tell it). This means that the SBP-2
- * device decides the actual maximum data it can transfer. We just tell it
- * the speed that it needs to use, and the max_rec the host supports, and
- * it takes care of the rest.
- */
-static int sbp2_max_speed_and_size(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- u8 payload;
-
- lu->speed_code = hi->host->speed[NODEID_TO_NODE(lu->ne->nodeid)];
-
- if (lu->speed_code > sbp2_max_speed) {
- lu->speed_code = sbp2_max_speed;
- SBP2_INFO("Reducing speed to %s",
- hpsb_speedto_str[sbp2_max_speed]);
- }
-
- /* Payload size is the lesser of what our speed supports and what
- * our host supports. */
- payload = min(sbp2_speedto_max_payload[lu->speed_code],
- (u8) (hi->host->csr.max_rec - 1));
-
- /* If physical DMA is off, work around limitation in ohci1394:
- * packet size must not exceed PAGE_SIZE */
- if (lu->ne->host->low_addr_space < (1ULL << 32))
- while (SBP2_PAYLOAD_TO_BYTES(payload) + 24 > PAGE_SIZE &&
- payload)
- payload--;
-
- SBP2_INFO("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
- NODE_BUS_ARGS(hi->host, lu->ne->nodeid),
- hpsb_speedto_str[lu->speed_code],
- SBP2_PAYLOAD_TO_BYTES(payload));
-
- lu->max_payload_size = payload;
- return 0;
-}
-
-static int sbp2_agent_reset(struct sbp2_lu *lu, int wait)
-{
- quadlet_t data;
- u64 addr;
- int retval;
- unsigned long flags;
-
- /* flush lu->protocol_work */
- if (wait)
- flush_scheduled_work();
-
- data = ntohl(SBP2_AGENT_RESET_DATA);
- addr = lu->command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;
-
- if (wait)
- retval = hpsb_node_write(lu->ne, addr, &data, 4);
- else
- retval = sbp2util_node_write_no_wait(lu->ne, addr, &data, 4);
-
- if (retval < 0) {
- SBP2_ERR("hpsb_node_write failed.\n");
- return -EIO;
- }
-
- /* make sure that the ORB_POINTER is written on next command */
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- lu->last_orb = NULL;
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- return 0;
-}
-
-static int sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
- struct sbp2_fwhost_info *hi,
- struct sbp2_command_info *cmd,
- unsigned int sg_count,
- struct scatterlist *sg,
- u32 orb_direction,
- enum dma_data_direction dma_dir)
-{
- struct device *dmadev = hi->host->device.parent;
- struct sbp2_unrestricted_page_table *pt;
- int i, n;
-
- n = dma_map_sg(dmadev, sg, sg_count, dma_dir);
- if (n == 0)
- return -ENOMEM;
-
- orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
- orb->misc |= ORB_SET_DIRECTION(orb_direction);
-
- /* special case if only one element (and less than 64KB in size) */
- if (n == 1) {
- orb->misc |= ORB_SET_DATA_SIZE(sg_dma_len(sg));
- orb->data_descriptor_lo = sg_dma_address(sg);
- } else {
- pt = &cmd->scatter_gather_element[0];
-
- dma_sync_single_for_cpu(dmadev, cmd->sge_dma,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
-
- for_each_sg(sg, sg, n, i) {
- pt[i].high = cpu_to_be32(sg_dma_len(sg) << 16);
- pt[i].low = cpu_to_be32(sg_dma_address(sg));
- }
-
- orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1) |
- ORB_SET_DATA_SIZE(n);
- orb->data_descriptor_lo = cmd->sge_dma;
-
- dma_sync_single_for_device(dmadev, cmd->sge_dma,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
- }
- return 0;
-}
-
-static int sbp2_create_command_orb(struct sbp2_lu *lu,
- struct sbp2_command_info *cmd,
- struct scsi_cmnd *SCpnt)
-{
- struct device *dmadev = lu->hi->host->device.parent;
- struct sbp2_command_orb *orb = &cmd->command_orb;
- unsigned int scsi_request_bufflen = scsi_bufflen(SCpnt);
- enum dma_data_direction dma_dir = SCpnt->sc_data_direction;
- u32 orb_direction;
- int ret;
-
- dma_sync_single_for_cpu(dmadev, cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
- /*
- * Set-up our command ORB.
- *
- * NOTE: We're doing unrestricted page tables (s/g), as this is
- * best performance (at least with the devices I have). This means
- * that data_size becomes the number of s/g elements, and
- * page_size should be zero (for unrestricted).
- */
- orb->next_ORB_hi = ORB_SET_NULL_PTR(1);
- orb->next_ORB_lo = 0x0;
- orb->misc = ORB_SET_MAX_PAYLOAD(lu->max_payload_size);
- orb->misc |= ORB_SET_SPEED(lu->speed_code);
- orb->misc |= ORB_SET_NOTIFY(1);
-
- if (dma_dir == DMA_NONE)
- orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
- else if (dma_dir == DMA_TO_DEVICE && scsi_request_bufflen)
- orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;
- else if (dma_dir == DMA_FROM_DEVICE && scsi_request_bufflen)
- orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;
- else {
- SBP2_INFO("Falling back to DMA_NONE");
- orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
- }
-
- /* set up our page table stuff */
- if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) {
- orb->data_descriptor_hi = 0x0;
- orb->data_descriptor_lo = 0x0;
- orb->misc |= ORB_SET_DIRECTION(1);
- ret = 0;
- } else {
- ret = sbp2_prep_command_orb_sg(orb, lu->hi, cmd,
- scsi_sg_count(SCpnt),
- scsi_sglist(SCpnt),
- orb_direction, dma_dir);
- }
- sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb));
-
- memset(orb->cdb, 0, sizeof(orb->cdb));
- memcpy(orb->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
- dma_sync_single_for_device(dmadev, cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
- return ret;
-}
-
-static void sbp2_link_orb_command(struct sbp2_lu *lu,
- struct sbp2_command_info *cmd)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- struct sbp2_command_orb *last_orb;
- dma_addr_t last_orb_dma;
- u64 addr = lu->command_block_agent_addr;
- quadlet_t data[2];
- size_t length;
- unsigned long flags;
-
- /* check to see if there are any previous orbs to use */
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- last_orb = lu->last_orb;
- last_orb_dma = lu->last_orb_dma;
- if (!last_orb) {
- /*
- * last_orb == NULL means: We know that the target's fetch agent
- * is not active right now.
- */
- addr += SBP2_ORB_POINTER_OFFSET;
- data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- data[1] = cmd->command_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
- length = 8;
- } else {
- /*
- * last_orb != NULL means: We know that the target's fetch agent
- * is (very probably) not dead or in reset state right now.
- * We have an ORB already sent that we can append a new one to.
- * The target's fetch agent may or may not have read this
- * previous ORB yet.
- */
- dma_sync_single_for_cpu(hi->host->device.parent, last_orb_dma,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- last_orb->next_ORB_lo = cpu_to_be32(cmd->command_orb_dma);
- wmb();
- /* Tells hardware that this pointer is valid */
- last_orb->next_ORB_hi = 0;
- dma_sync_single_for_device(hi->host->device.parent,
- last_orb_dma,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- addr += SBP2_DOORBELL_OFFSET;
- data[0] = 0;
- length = 4;
- }
- lu->last_orb = &cmd->command_orb;
- lu->last_orb_dma = cmd->command_orb_dma;
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- if (sbp2util_node_write_no_wait(lu->ne, addr, data, length)) {
- /*
- * sbp2util_node_write_no_wait failed. We certainly ran out
- * of transaction labels, perhaps just because there were no
- * context switches which gave khpsbpkt a chance to collect
- * free tlabels. Try again in non-atomic context. If necessary,
- * the workqueue job will sleep to guaranteedly get a tlabel.
- * We do not accept new commands until the job is over.
- */
- scsi_block_requests(lu->shost);
- PREPARE_WORK(&lu->protocol_work,
- last_orb ? sbp2util_write_doorbell:
- sbp2util_write_orb_pointer);
- schedule_work(&lu->protocol_work);
- }
-}
-
-static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt,
- void (*done)(struct scsi_cmnd *))
-{
- struct sbp2_command_info *cmd;
-
- cmd = sbp2util_allocate_command_orb(lu, SCpnt, done);
- if (!cmd)
- return -EIO;
-
- if (sbp2_create_command_orb(lu, cmd, SCpnt))
- return -ENOMEM;
-
- sbp2_link_orb_command(lu, cmd);
- return 0;
-}
-
-/*
- * Translates SBP-2 status into SCSI sense data for check conditions
- */
-static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status,
- unchar *sense_data)
-{
- /* OK, it's pretty ugly... ;-) */
- sense_data[0] = 0x70;
- sense_data[1] = 0x0;
- sense_data[2] = sbp2_status[9];
- sense_data[3] = sbp2_status[12];
- sense_data[4] = sbp2_status[13];
- sense_data[5] = sbp2_status[14];
- sense_data[6] = sbp2_status[15];
- sense_data[7] = 10;
- sense_data[8] = sbp2_status[16];
- sense_data[9] = sbp2_status[17];
- sense_data[10] = sbp2_status[18];
- sense_data[11] = sbp2_status[19];
- sense_data[12] = sbp2_status[10];
- sense_data[13] = sbp2_status[11];
- sense_data[14] = sbp2_status[20];
- sense_data[15] = sbp2_status[21];
-
- return sbp2_status[8] & 0x3f;
-}
-
-static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
- int destid, quadlet_t *data, u64 addr,
- size_t length, u16 fl)
-{
- struct sbp2_fwhost_info *hi;
- struct sbp2_lu *lu = NULL, *lu_tmp;
- struct scsi_cmnd *SCpnt = NULL;
- struct sbp2_status_block *sb;
- u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
- struct sbp2_command_info *cmd;
- unsigned long flags;
-
- if (unlikely(length < 8 || length > sizeof(struct sbp2_status_block))) {
- SBP2_ERR("Wrong size of status block");
- return RCODE_ADDRESS_ERROR;
- }
- if (unlikely(!host)) {
- SBP2_ERR("host is NULL - this is bad!");
- return RCODE_ADDRESS_ERROR;
- }
- hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
- if (unlikely(!hi)) {
- SBP2_ERR("host info is NULL - this is bad!");
- return RCODE_ADDRESS_ERROR;
- }
-
- /* Find the unit which wrote the status. */
- read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
- list_for_each_entry(lu_tmp, &hi->logical_units, lu_list) {
- if (lu_tmp->ne->nodeid == nodeid &&
- lu_tmp->status_fifo_addr == addr) {
- lu = lu_tmp;
- break;
- }
- }
- read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
- if (unlikely(!lu)) {
- SBP2_ERR("lu is NULL - device is gone?");
- return RCODE_ADDRESS_ERROR;
- }
-
- /* Put response into lu status fifo buffer. The first two bytes
- * come in big endian bit order. Often the target writes only a
- * truncated status block, minimally the first two quadlets. The rest
- * is implied to be zeros. */
- sb = &lu->status_block;
- memset(sb->command_set_dependent, 0, sizeof(sb->command_set_dependent));
- memcpy(sb, data, length);
- sbp2util_be32_to_cpu_buffer(sb, 8);
-
- /* Ignore unsolicited status. Handle command ORB status. */
- if (unlikely(STATUS_GET_SRC(sb->ORB_offset_hi_misc) == 2))
- cmd = NULL;
- else
- cmd = sbp2util_find_command_for_orb(lu, sb->ORB_offset_lo);
- if (cmd) {
- /* Grab SCSI command pointers and check status. */
- /*
- * FIXME: If the src field in the status is 1, the ORB DMA must
- * not be reused until status for a subsequent ORB is received.
- */
- SCpnt = cmd->Current_SCpnt;
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- sbp2util_mark_command_completed(lu, cmd);
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- if (SCpnt) {
- u32 h = sb->ORB_offset_hi_misc;
- u32 r = STATUS_GET_RESP(h);
-
- if (r != RESP_STATUS_REQUEST_COMPLETE) {
- SBP2_INFO("resp 0x%x, sbp_status 0x%x",
- r, STATUS_GET_SBP_STATUS(h));
- scsi_status =
- r == RESP_STATUS_TRANSPORT_FAILURE ?
- SBP2_SCSI_STATUS_BUSY :
- SBP2_SCSI_STATUS_COMMAND_TERMINATED;
- }
-
- if (STATUS_GET_LEN(h) > 1)
- scsi_status = sbp2_status_to_sense_data(
- (unchar *)sb, SCpnt->sense_buffer);
-
- if (STATUS_TEST_DEAD(h))
- sbp2_agent_reset(lu, 0);
- }
-
- /* Check here to see if there are no commands in-use. If there
- * are none, we know that the fetch agent left the active state
- * _and_ that we did not reactivate it yet. Therefore clear
- * last_orb so that next time we write directly to the
- * ORB_POINTER register. That way the fetch agent does not need
- * to refetch the next_ORB. */
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- if (list_empty(&lu->cmd_orb_inuse))
- lu->last_orb = NULL;
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- } else {
- /* It's probably status after a management request. */
- if ((sb->ORB_offset_lo == lu->reconnect_orb_dma) ||
- (sb->ORB_offset_lo == lu->login_orb_dma) ||
- (sb->ORB_offset_lo == lu->query_logins_orb_dma) ||
- (sb->ORB_offset_lo == lu->logout_orb_dma)) {
- lu->access_complete = 1;
- wake_up_interruptible(&sbp2_access_wq);
- }
- }
-
- if (SCpnt)
- sbp2scsi_complete_command(lu, scsi_status, SCpnt,
- cmd->Current_done);
- return RCODE_COMPLETE;
-}
-
-/**************************************
- * SCSI interface related section
- **************************************/
-
-static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt,
- void (*done)(struct scsi_cmnd *))
-{
- struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
- struct sbp2_fwhost_info *hi;
- int result = DID_NO_CONNECT << 16;
-
- if (unlikely(!sbp2util_node_is_available(lu)))
- goto done;
-
- hi = lu->hi;
-
- if (unlikely(!hi)) {
- SBP2_ERR("sbp2_fwhost_info is NULL - this is bad!");
- goto done;
- }
-
- /* Multiple units are currently represented to the SCSI core as separate
- * targets, not as one target with multiple LUs. Therefore return
- * selection time-out to any IO directed at non-zero LUNs. */
- if (unlikely(SCpnt->device->lun))
- goto done;
-
- if (unlikely(!hpsb_node_entry_valid(lu->ne))) {
- SBP2_ERR("Bus reset in progress - rejecting command");
- result = DID_BUS_BUSY << 16;
- goto done;
- }
-
- /* Bidirectional commands are not yet implemented,
- * and unknown transfer direction not handled. */
- if (unlikely(SCpnt->sc_data_direction == DMA_BIDIRECTIONAL)) {
- SBP2_ERR("Cannot handle DMA_BIDIRECTIONAL - rejecting command");
- result = DID_ERROR << 16;
- goto done;
- }
-
- if (sbp2_send_command(lu, SCpnt, done)) {
- SBP2_ERR("Error sending SCSI command");
- sbp2scsi_complete_command(lu,
- SBP2_SCSI_STATUS_SELECTION_TIMEOUT,
- SCpnt, done);
- }
- return 0;
-
-done:
- SCpnt->result = result;
- done(SCpnt);
- return 0;
-}
-
-static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status)
-{
- struct list_head *lh;
- struct sbp2_command_info *cmd;
- unsigned long flags;
-
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- while (!list_empty(&lu->cmd_orb_inuse)) {
- lh = lu->cmd_orb_inuse.next;
- cmd = list_entry(lh, struct sbp2_command_info, list);
- sbp2util_mark_command_completed(lu, cmd);
- if (cmd->Current_SCpnt) {
- cmd->Current_SCpnt->result = status << 16;
- cmd->Current_done(cmd->Current_SCpnt);
- }
- }
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- return;
-}
-
-/*
- * Complete a regular SCSI command. Can be called in atomic context.
- */
-static void sbp2scsi_complete_command(struct sbp2_lu *lu, u32 scsi_status,
- struct scsi_cmnd *SCpnt,
- void (*done)(struct scsi_cmnd *))
-{
- if (!SCpnt) {
- SBP2_ERR("SCpnt is NULL");
- return;
- }
-
- switch (scsi_status) {
- case SBP2_SCSI_STATUS_GOOD:
- SCpnt->result = DID_OK << 16;
- break;
-
- case SBP2_SCSI_STATUS_BUSY:
- SBP2_ERR("SBP2_SCSI_STATUS_BUSY");
- SCpnt->result = DID_BUS_BUSY << 16;
- break;
-
- case SBP2_SCSI_STATUS_CHECK_CONDITION:
- SCpnt->result = CHECK_CONDITION << 1 | DID_OK << 16;
- break;
-
- case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
- SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
- SCpnt->result = DID_NO_CONNECT << 16;
- scsi_print_command(SCpnt);
- break;
-
- case SBP2_SCSI_STATUS_CONDITION_MET:
- case SBP2_SCSI_STATUS_RESERVATION_CONFLICT:
- case SBP2_SCSI_STATUS_COMMAND_TERMINATED:
- SBP2_ERR("Bad SCSI status = %x", scsi_status);
- SCpnt->result = DID_ERROR << 16;
- scsi_print_command(SCpnt);
- break;
-
- default:
- SBP2_ERR("Unsupported SCSI status = %x", scsi_status);
- SCpnt->result = DID_ERROR << 16;
- }
-
- /* If a bus reset is in progress and there was an error, complete
- * the command as busy so that it will get retried. */
- if (!hpsb_node_entry_valid(lu->ne)
- && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
- SBP2_ERR("Completing command with busy (bus reset)");
- SCpnt->result = DID_BUS_BUSY << 16;
- }
-
- /* Tell the SCSI stack that we're done with this command. */
- done(SCpnt);
-}
-
-static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
-{
- struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
-
- if (sdev->lun != 0 || sdev->id != lu->ud->id || sdev->channel != 0)
- return -ENODEV;
-
- lu->sdev = sdev;
- sdev->allow_restart = 1;
-
- /* SBP-2 requires quadlet alignment of the data buffers. */
- blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1);
-
- if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36)
- sdev->inquiry_len = 36;
- return 0;
-}
-
-static int sbp2scsi_slave_configure(struct scsi_device *sdev)
-{
- struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
-
- sdev->use_10_for_rw = 1;
-
- if (sbp2_exclusive_login)
- sdev->manage_start_stop = 1;
- if (sdev->type == TYPE_ROM)
- sdev->use_10_for_ms = 1;
- if (sdev->type == TYPE_DISK &&
- lu->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
- sdev->skip_ms_page_8 = 1;
- if (lu->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
- sdev->fix_capacity = 1;
- if (lu->workarounds & SBP2_WORKAROUND_POWER_CONDITION)
- sdev->start_stop_pwr_cond = 1;
- if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
- blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512);
-
- blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
- return 0;
-}
-
-static void sbp2scsi_slave_destroy(struct scsi_device *sdev)
-{
- ((struct sbp2_lu *)sdev->host->hostdata[0])->sdev = NULL;
- return;
-}
-
-/*
- * Called by scsi stack when something has really gone wrong.
- * Usually called when a command has timed-out for some reason.
- */
-static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
-{
- struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
- struct sbp2_command_info *cmd;
- unsigned long flags;
-
- SBP2_INFO("aborting sbp2 command");
- scsi_print_command(SCpnt);
-
- if (sbp2util_node_is_available(lu)) {
- sbp2_agent_reset(lu, 1);
-
- /* Return a matching command structure to the free pool. */
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- cmd = sbp2util_find_command_for_SCpnt(lu, SCpnt);
- if (cmd) {
- sbp2util_mark_command_completed(lu, cmd);
- if (cmd->Current_SCpnt) {
- cmd->Current_SCpnt->result = DID_ABORT << 16;
- cmd->Current_done(cmd->Current_SCpnt);
- }
- }
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY);
- }
-
- return SUCCESS;
-}
-
-/*
- * Called by scsi stack when something has really gone wrong.
- */
-static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
-{
- struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
-
- SBP2_INFO("reset requested");
-
- if (sbp2util_node_is_available(lu)) {
- SBP2_INFO("generating sbp2 fetch agent reset");
- sbp2_agent_reset(lu, 1);
- }
-
- return SUCCESS;
-}
-
-static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct scsi_device *sdev;
- struct sbp2_lu *lu;
-
- if (!(sdev = to_scsi_device(dev)))
- return 0;
-
- if (!(lu = (struct sbp2_lu *)sdev->host->hostdata[0]))
- return 0;
-
- if (sbp2_long_sysfs_ieee1394_id)
- return sprintf(buf, "%016Lx:%06x:%04x\n",
- (unsigned long long)lu->ne->guid,
- lu->ud->directory_id, ORB_SET_LUN(lu->lun));
- else
- return sprintf(buf, "%016Lx:%d:%d\n",
- (unsigned long long)lu->ne->guid,
- lu->ud->id, ORB_SET_LUN(lu->lun));
-}
-
-MODULE_AUTHOR("Ben Collins <bcollins@debian.org>");
-MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
-MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
-MODULE_LICENSE("GPL");
-
-static int sbp2_module_init(void)
-{
- int ret;
-
- if (sbp2_serialize_io) {
- sbp2_shost_template.can_queue = 1;
- sbp2_shost_template.cmd_per_lun = 1;
- }
-
- sbp2_shost_template.max_sectors = sbp2_max_sectors;
-
- hpsb_register_highlevel(&sbp2_highlevel);
- ret = hpsb_register_protocol(&sbp2_driver);
- if (ret) {
- SBP2_ERR("Failed to register protocol");
- hpsb_unregister_highlevel(&sbp2_highlevel);
- return ret;
- }
- return 0;
-}
-
-static void __exit sbp2_module_exit(void)
-{
- hpsb_unregister_protocol(&sbp2_driver);
- hpsb_unregister_highlevel(&sbp2_highlevel);
-}
-
-module_init(sbp2_module_init);
-module_exit(sbp2_module_exit);
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
deleted file mode 100644
index 64a3a66a8a39..000000000000
--- a/drivers/ieee1394/sbp2.h
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * sbp2.h - Defines and prototypes for sbp2.c
- *
- * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef SBP2_H
-#define SBP2_H
-
-#define SBP2_DEVICE_NAME "sbp2"
-
-/*
- * There is no transport protocol limit to the CDB length, but we implement
- * a fixed length only. 16 bytes is enough for disks larger than 2 TB.
- */
-#define SBP2_MAX_CDB_SIZE 16
-
-/*
- * SBP-2 specific definitions
- */
-
-#define ORB_DIRECTION_WRITE_TO_MEDIA 0x0
-#define ORB_DIRECTION_READ_FROM_MEDIA 0x1
-#define ORB_DIRECTION_NO_DATA_TRANSFER 0x2
-
-#define ORB_SET_NULL_PTR(v) (((v) & 0x1) << 31)
-#define ORB_SET_NOTIFY(v) (((v) & 0x1) << 31)
-#define ORB_SET_RQ_FMT(v) (((v) & 0x3) << 29)
-#define ORB_SET_NODE_ID(v) (((v) & 0xffff) << 16)
-#define ORB_SET_STATUS_FIFO_HI(v, id) ((v) >> 32 | ORB_SET_NODE_ID(id))
-#define ORB_SET_STATUS_FIFO_LO(v) ((v) & 0xffffffff)
-#define ORB_SET_DATA_SIZE(v) ((v) & 0xffff)
-#define ORB_SET_PAGE_SIZE(v) (((v) & 0x7) << 16)
-#define ORB_SET_PAGE_TABLE_PRESENT(v) (((v) & 0x1) << 19)
-#define ORB_SET_MAX_PAYLOAD(v) (((v) & 0xf) << 20)
-#define ORB_SET_SPEED(v) (((v) & 0x7) << 24)
-#define ORB_SET_DIRECTION(v) (((v) & 0x1) << 27)
-
-struct sbp2_command_orb {
- u32 next_ORB_hi;
- u32 next_ORB_lo;
- u32 data_descriptor_hi;
- u32 data_descriptor_lo;
- u32 misc;
- u8 cdb[SBP2_MAX_CDB_SIZE];
-} __attribute__((packed));
-
-#define SBP2_LOGIN_REQUEST 0x0
-#define SBP2_QUERY_LOGINS_REQUEST 0x1
-#define SBP2_RECONNECT_REQUEST 0x3
-#define SBP2_SET_PASSWORD_REQUEST 0x4
-#define SBP2_LOGOUT_REQUEST 0x7
-#define SBP2_ABORT_TASK_REQUEST 0xb
-#define SBP2_ABORT_TASK_SET 0xc
-#define SBP2_LOGICAL_UNIT_RESET 0xe
-#define SBP2_TARGET_RESET_REQUEST 0xf
-
-#define ORB_SET_LUN(v) ((v) & 0xffff)
-#define ORB_SET_FUNCTION(v) (((v) & 0xf) << 16)
-#define ORB_SET_RECONNECT(v) (((v) & 0xf) << 20)
-#define ORB_SET_EXCLUSIVE(v) ((v) ? 1 << 28 : 0)
-#define ORB_SET_LOGIN_RESP_LENGTH(v) ((v) & 0xffff)
-#define ORB_SET_PASSWD_LENGTH(v) (((v) & 0xffff) << 16)
-
-struct sbp2_login_orb {
- u32 password_hi;
- u32 password_lo;
- u32 login_response_hi;
- u32 login_response_lo;
- u32 lun_misc;
- u32 passwd_resp_lengths;
- u32 status_fifo_hi;
- u32 status_fifo_lo;
-} __attribute__((packed));
-
-#define RESPONSE_GET_LOGIN_ID(v) ((v) & 0xffff)
-#define RESPONSE_GET_LENGTH(v) (((v) >> 16) & 0xffff)
-#define RESPONSE_GET_RECONNECT_HOLD(v) ((v) & 0xffff)
-
-struct sbp2_login_response {
- u32 length_login_ID;
- u32 command_block_agent_hi;
- u32 command_block_agent_lo;
- u32 reconnect_hold;
-} __attribute__((packed));
-
-#define ORB_SET_LOGIN_ID(v) ((v) & 0xffff)
-#define ORB_SET_QUERY_LOGINS_RESP_LENGTH(v) ((v) & 0xffff)
-
-struct sbp2_query_logins_orb {
- u32 reserved1;
- u32 reserved2;
- u32 query_response_hi;
- u32 query_response_lo;
- u32 lun_misc;
- u32 reserved_resp_length;
- u32 status_fifo_hi;
- u32 status_fifo_lo;
-} __attribute__((packed));
-
-#define RESPONSE_GET_MAX_LOGINS(v) ((v) & 0xffff)
-#define RESPONSE_GET_ACTIVE_LOGINS(v) ((RESPONSE_GET_LENGTH((v)) - 4) / 12)
-
-struct sbp2_query_logins_response {
- u32 length_max_logins;
- u32 misc_IDs;
- u32 initiator_misc_hi;
- u32 initiator_misc_lo;
-} __attribute__((packed));
-
-struct sbp2_reconnect_orb {
- u32 reserved1;
- u32 reserved2;
- u32 reserved3;
- u32 reserved4;
- u32 login_ID_misc;
- u32 reserved5;
- u32 status_fifo_hi;
- u32 status_fifo_lo;
-} __attribute__((packed));
-
-struct sbp2_logout_orb {
- u32 reserved1;
- u32 reserved2;
- u32 reserved3;
- u32 reserved4;
- u32 login_ID_misc;
- u32 reserved5;
- u32 status_fifo_hi;
- u32 status_fifo_lo;
-} __attribute__((packed));
-
-struct sbp2_unrestricted_page_table {
- __be32 high;
- __be32 low;
-};
-
-#define RESP_STATUS_REQUEST_COMPLETE 0x0
-#define RESP_STATUS_TRANSPORT_FAILURE 0x1
-#define RESP_STATUS_ILLEGAL_REQUEST 0x2
-#define RESP_STATUS_VENDOR_DEPENDENT 0x3
-
-#define SBP2_STATUS_NO_ADDITIONAL_INFO 0x0
-#define SBP2_STATUS_REQ_TYPE_NOT_SUPPORTED 0x1
-#define SBP2_STATUS_SPEED_NOT_SUPPORTED 0x2
-#define SBP2_STATUS_PAGE_SIZE_NOT_SUPPORTED 0x3
-#define SBP2_STATUS_ACCESS_DENIED 0x4
-#define SBP2_STATUS_LU_NOT_SUPPORTED 0x5
-#define SBP2_STATUS_MAX_PAYLOAD_TOO_SMALL 0x6
-#define SBP2_STATUS_RESOURCES_UNAVAILABLE 0x8
-#define SBP2_STATUS_FUNCTION_REJECTED 0x9
-#define SBP2_STATUS_LOGIN_ID_NOT_RECOGNIZED 0xa
-#define SBP2_STATUS_DUMMY_ORB_COMPLETED 0xb
-#define SBP2_STATUS_REQUEST_ABORTED 0xc
-#define SBP2_STATUS_UNSPECIFIED_ERROR 0xff
-
-#define SFMT_CURRENT_ERROR 0x0
-#define SFMT_DEFERRED_ERROR 0x1
-#define SFMT_VENDOR_DEPENDENT_STATUS 0x3
-
-#define STATUS_GET_SRC(v) (((v) >> 30) & 0x3)
-#define STATUS_GET_RESP(v) (((v) >> 28) & 0x3)
-#define STATUS_GET_LEN(v) (((v) >> 24) & 0x7)
-#define STATUS_GET_SBP_STATUS(v) (((v) >> 16) & 0xff)
-#define STATUS_GET_ORB_OFFSET_HI(v) ((v) & 0x0000ffff)
-#define STATUS_TEST_DEAD(v) ((v) & 0x08000000)
-/* test 'resp' | 'dead' | 'sbp2_status' */
-#define STATUS_TEST_RDS(v) ((v) & 0x38ff0000)
-
-struct sbp2_status_block {
- u32 ORB_offset_hi_misc;
- u32 ORB_offset_lo;
- u8 command_set_dependent[24];
-} __attribute__((packed));
-
-
-/*
- * SBP2 related configuration ROM definitions
- */
-
-#define SBP2_UNIT_DIRECTORY_OFFSET_KEY 0xd1
-#define SBP2_CSR_OFFSET_KEY 0x54
-#define SBP2_UNIT_SPEC_ID_KEY 0x12
-#define SBP2_UNIT_SW_VERSION_KEY 0x13
-#define SBP2_COMMAND_SET_SPEC_ID_KEY 0x38
-#define SBP2_COMMAND_SET_KEY 0x39
-#define SBP2_UNIT_CHARACTERISTICS_KEY 0x3a
-#define SBP2_DEVICE_TYPE_AND_LUN_KEY 0x14
-#define SBP2_FIRMWARE_REVISION_KEY 0x3c
-
-#define SBP2_AGENT_STATE_OFFSET 0x00ULL
-#define SBP2_AGENT_RESET_OFFSET 0x04ULL
-#define SBP2_ORB_POINTER_OFFSET 0x08ULL
-#define SBP2_DOORBELL_OFFSET 0x10ULL
-#define SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET 0x14ULL
-#define SBP2_UNSOLICITED_STATUS_VALUE 0xf
-
-#define SBP2_BUSY_TIMEOUT_ADDRESS 0xfffff0000210ULL
-/* biggest possible value for Single Phase Retry count is 0xf */
-#define SBP2_BUSY_TIMEOUT_VALUE 0xf
-
-#define SBP2_AGENT_RESET_DATA 0xf
-
-#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e
-#define SBP2_SW_VERSION_ENTRY 0x00010483
-
-/*
- * The default maximum s/g segment size of a FireWire controller is
- * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
- * be quadlet-aligned, we set the length limit to 0xffff & ~3.
- */
-#define SBP2_MAX_SEG_SIZE 0xfffc
-
-/*
- * There is no real limitation of the queue depth (i.e. length of the linked
- * list of command ORBs) at the target. The chosen depth is merely an
- * implementation detail of the sbp2 driver.
- */
-#define SBP2_MAX_CMDS 8
-
-#define SBP2_SCSI_STATUS_GOOD 0x0
-#define SBP2_SCSI_STATUS_CHECK_CONDITION 0x2
-#define SBP2_SCSI_STATUS_CONDITION_MET 0x4
-#define SBP2_SCSI_STATUS_BUSY 0x8
-#define SBP2_SCSI_STATUS_RESERVATION_CONFLICT 0x18
-#define SBP2_SCSI_STATUS_COMMAND_TERMINATED 0x22
-#define SBP2_SCSI_STATUS_SELECTION_TIMEOUT 0xff
-
-
-/*
- * Representations of commands and devices
- */
-
-/* Per SCSI command */
-struct sbp2_command_info {
- struct list_head list;
- struct sbp2_command_orb command_orb;
- dma_addr_t command_orb_dma;
- struct scsi_cmnd *Current_SCpnt;
- void (*Current_done)(struct scsi_cmnd *);
-
- /* Also need s/g structure for each sbp2 command */
- struct sbp2_unrestricted_page_table
- scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
- dma_addr_t sge_dma;
-};
-
-/* Per FireWire host */
-struct sbp2_fwhost_info {
- struct hpsb_host *host;
- struct list_head logical_units;
-};
-
-/* Per logical unit */
-struct sbp2_lu {
- /* Operation request blocks */
- struct sbp2_command_orb *last_orb;
- dma_addr_t last_orb_dma;
- struct sbp2_login_orb *login_orb;
- dma_addr_t login_orb_dma;
- struct sbp2_login_response *login_response;
- dma_addr_t login_response_dma;
- struct sbp2_query_logins_orb *query_logins_orb;
- dma_addr_t query_logins_orb_dma;
- struct sbp2_query_logins_response *query_logins_response;
- dma_addr_t query_logins_response_dma;
- struct sbp2_reconnect_orb *reconnect_orb;
- dma_addr_t reconnect_orb_dma;
- struct sbp2_logout_orb *logout_orb;
- dma_addr_t logout_orb_dma;
- struct sbp2_status_block status_block;
-
- /* How to talk to the unit */
- u64 management_agent_addr;
- u64 command_block_agent_addr;
- u32 speed_code;
- u32 max_payload_size;
- u16 lun;
-
- /* Address for the unit to write status blocks to */
- u64 status_fifo_addr;
-
- /* Waitqueue flag for logins, reconnects, logouts, query logins */
- unsigned int access_complete:1;
-
- /* Pool of command ORBs for this logical unit */
- spinlock_t cmd_orb_lock;
- struct list_head cmd_orb_inuse;
- struct list_head cmd_orb_completed;
-
- /* Backlink to FireWire host; list of units attached to the host */
- struct sbp2_fwhost_info *hi;
- struct list_head lu_list;
-
- /* IEEE 1394 core's device representations */
- struct node_entry *ne;
- struct unit_directory *ud;
-
- /* SCSI core's device representations */
- struct scsi_device *sdev;
- struct Scsi_Host *shost;
-
- /* Device specific workarounds/brokeness */
- unsigned workarounds;
-
- /* Connection state */
- atomic_t state;
-
- /* For deferred requests to the fetch agent */
- struct work_struct protocol_work;
-};
-
-/* For use in sbp2_lu.state */
-enum sbp2lu_state_types {
- SBP2LU_STATE_RUNNING, /* all normal */
- SBP2LU_STATE_IN_RESET, /* between bus reset and reconnect */
- SBP2LU_STATE_IN_SHUTDOWN /* when sbp2_remove was called */
-};
-
-/* For use in sbp2_lu.workarounds and in the corresponding
- * module load parameter */
-#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
-#define SBP2_WORKAROUND_INQUIRY_36 0x2
-#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
-#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
-#define SBP2_WORKAROUND_DELAY_INQUIRY 0x10
-#define SBP2_INQUIRY_DELAY 12
-#define SBP2_WORKAROUND_POWER_CONDITION 0x20
-#define SBP2_WORKAROUND_OVERRIDE 0x100
-
-#endif /* SBP2_H */
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
deleted file mode 100644
index 5c74f796d7f1..000000000000
--- a/drivers/ieee1394/video1394.c
+++ /dev/null
@@ -1,1528 +0,0 @@
-/*
- * video1394.c - video driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * NOTES:
- *
- * ioctl return codes:
- * EFAULT is only for invalid address for the argp
- * EINVAL for out of range values
- * EBUSY when trying to use an already used resource
- * ESRCH when trying to free/stop a not used resource
- * EAGAIN for resource allocation failure that could perhaps succeed later
- * ENOTTY for unsupported ioctl request
- *
- */
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/timex.h>
-#include <linux/mm.h>
-#include <linux/compat.h>
-#include <linux/cdev.h>
-
-#include "dma.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "ohci1394.h"
-#include "video1394.h"
-
-#define ISO_CHANNELS 64
-
-struct it_dma_prg {
- struct dma_cmd begin;
- quadlet_t data[4];
- struct dma_cmd end;
- quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
-};
-
-struct dma_iso_ctx {
- struct ti_ohci *ohci;
- int type; /* OHCI_ISO_TRANSMIT or OHCI_ISO_RECEIVE */
- struct ohci1394_iso_tasklet iso_tasklet;
- int channel;
- int ctx;
- int last_buffer;
- int * next_buffer; /* For ISO Transmit of video packets
- to write the correct SYT field
- into the next block */
- unsigned int num_desc;
- unsigned int buf_size;
- unsigned int frame_size;
- unsigned int packet_size;
- unsigned int left_size;
- unsigned int nb_cmd;
-
- struct dma_region dma;
-
- struct dma_prog_region *prg_reg;
-
- struct dma_cmd **ir_prg;
- struct it_dma_prg **it_prg;
-
- unsigned int *buffer_status;
- unsigned int *buffer_prg_assignment;
- struct timeval *buffer_time; /* time when the buffer was received */
- unsigned int *last_used_cmd; /* For ISO Transmit with
- variable sized packets only ! */
- int ctrlClear;
- int ctrlSet;
- int cmdPtr;
- int ctxMatch;
- wait_queue_head_t waitq;
- spinlock_t lock;
- unsigned int syt_offset;
- int flags;
-
- struct list_head link;
-};
-
-
-struct file_ctx {
- struct ti_ohci *ohci;
- struct list_head context_list;
- struct dma_iso_ctx *current_ctx;
-};
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define VIDEO1394_DEBUG
-#endif
-
-#ifdef DBGMSG
-#undef DBGMSG
-#endif
-
-#ifdef VIDEO1394_DEBUG
-#define DBGMSG(card, fmt, args...) \
-printk(KERN_INFO "video1394_%d: " fmt "\n" , card , ## args)
-#else
-#define DBGMSG(card, fmt, args...) do {} while (0)
-#endif
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) \
-printk(level "video1394: " fmt "\n" , ## args)
-
-/* print card specific information */
-#define PRINT(level, card, fmt, args...) \
-printk(level "video1394_%d: " fmt "\n" , card , ## args)
-
-static void wakeup_dma_ir_ctx(unsigned long l);
-static void wakeup_dma_it_ctx(unsigned long l);
-
-static struct hpsb_highlevel video1394_highlevel;
-
-static int free_dma_iso_ctx(struct dma_iso_ctx *d)
-{
- int i;
-
- DBGMSG(d->ohci->host->id, "Freeing dma_iso_ctx %d", d->ctx);
-
- ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
- if (d->iso_tasklet.link.next != NULL)
- ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet);
-
- dma_region_free(&d->dma);
-
- if (d->prg_reg) {
- for (i = 0; i < d->num_desc; i++)
- dma_prog_region_free(&d->prg_reg[i]);
- kfree(d->prg_reg);
- }
-
- kfree(d->ir_prg);
- kfree(d->it_prg);
- kfree(d->buffer_status);
- kfree(d->buffer_prg_assignment);
- kfree(d->buffer_time);
- kfree(d->last_used_cmd);
- kfree(d->next_buffer);
- list_del(&d->link);
- kfree(d);
-
- return 0;
-}
-
-static struct dma_iso_ctx *
-alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
- int buf_size, int channel, unsigned int packet_size)
-{
- struct dma_iso_ctx *d;
- int i;
-
- d = kzalloc(sizeof(*d), GFP_KERNEL);
- if (!d) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma_iso_ctx");
- return NULL;
- }
-
- d->ohci = ohci;
- d->type = type;
- d->channel = channel;
- d->num_desc = num_desc;
- d->frame_size = buf_size;
- d->buf_size = PAGE_ALIGN(buf_size);
- d->last_buffer = -1;
- INIT_LIST_HEAD(&d->link);
- init_waitqueue_head(&d->waitq);
-
- /* Init the regions for easy cleanup */
- dma_region_init(&d->dma);
-
- if (dma_region_alloc(&d->dma, (d->num_desc - 1) * d->buf_size, ohci->dev,
- PCI_DMA_BIDIRECTIONAL)) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma buffer");
- free_dma_iso_ctx(d);
- return NULL;
- }
-
- if (type == OHCI_ISO_RECEIVE)
- ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
- wakeup_dma_ir_ctx,
- (unsigned long) d);
- else
- ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
- wakeup_dma_it_ctx,
- (unsigned long) d);
-
- if (ohci1394_register_iso_tasklet(ohci, &d->iso_tasklet) < 0) {
- PRINT(KERN_ERR, ohci->host->id, "no free iso %s contexts",
- type == OHCI_ISO_RECEIVE ? "receive" : "transmit");
- free_dma_iso_ctx(d);
- return NULL;
- }
- d->ctx = d->iso_tasklet.context;
-
- d->prg_reg = kmalloc(d->num_desc * sizeof(*d->prg_reg), GFP_KERNEL);
- if (!d->prg_reg) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate ir prg regs");
- free_dma_iso_ctx(d);
- return NULL;
- }
- /* Makes for easier cleanup */
- for (i = 0; i < d->num_desc; i++)
- dma_prog_region_init(&d->prg_reg[i]);
-
- if (type == OHCI_ISO_RECEIVE) {
- d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx;
- d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx;
- d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx;
- d->ctxMatch = OHCI1394_IsoRcvContextMatch+32*d->ctx;
-
- d->ir_prg = kzalloc(d->num_desc * sizeof(*d->ir_prg),
- GFP_KERNEL);
-
- if (!d->ir_prg) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg");
- free_dma_iso_ctx(d);
- return NULL;
- }
-
- d->nb_cmd = d->buf_size / PAGE_SIZE + 1;
- d->left_size = (d->frame_size % PAGE_SIZE) ?
- d->frame_size % PAGE_SIZE : PAGE_SIZE;
-
- for (i = 0;i < d->num_desc; i++) {
- if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
- sizeof(struct dma_cmd), ohci->dev)) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg");
- free_dma_iso_ctx(d);
- return NULL;
- }
- d->ir_prg[i] = (struct dma_cmd *)d->prg_reg[i].kvirt;
- }
-
- } else { /* OHCI_ISO_TRANSMIT */
- d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx;
- d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx;
- d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx;
-
- d->it_prg = kzalloc(d->num_desc * sizeof(*d->it_prg),
- GFP_KERNEL);
-
- if (!d->it_prg) {
- PRINT(KERN_ERR, ohci->host->id,
- "Failed to allocate dma it prg");
- free_dma_iso_ctx(d);
- return NULL;
- }
-
- d->packet_size = packet_size;
-
- if (PAGE_SIZE % packet_size || packet_size>4096) {
- PRINT(KERN_ERR, ohci->host->id,
- "Packet size %d (page_size: %ld) "
- "not yet supported\n",
- packet_size, PAGE_SIZE);
- free_dma_iso_ctx(d);
- return NULL;
- }
-
- d->nb_cmd = d->frame_size / d->packet_size;
- if (d->frame_size % d->packet_size) {
- d->nb_cmd++;
- d->left_size = d->frame_size % d->packet_size;
- } else
- d->left_size = d->packet_size;
-
- for (i = 0; i < d->num_desc; i++) {
- if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
- sizeof(struct it_dma_prg), ohci->dev)) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma it prg");
- free_dma_iso_ctx(d);
- return NULL;
- }
- d->it_prg[i] = (struct it_dma_prg *)d->prg_reg[i].kvirt;
- }
- }
-
- d->buffer_status =
- kzalloc(d->num_desc * sizeof(*d->buffer_status), GFP_KERNEL);
- d->buffer_prg_assignment =
- kzalloc(d->num_desc * sizeof(*d->buffer_prg_assignment), GFP_KERNEL);
- d->buffer_time =
- kzalloc(d->num_desc * sizeof(*d->buffer_time), GFP_KERNEL);
- d->last_used_cmd =
- kzalloc(d->num_desc * sizeof(*d->last_used_cmd), GFP_KERNEL);
- d->next_buffer =
- kzalloc(d->num_desc * sizeof(*d->next_buffer), GFP_KERNEL);
-
- if (!d->buffer_status || !d->buffer_prg_assignment || !d->buffer_time ||
- !d->last_used_cmd || !d->next_buffer) {
- PRINT(KERN_ERR, ohci->host->id,
- "Failed to allocate dma_iso_ctx member");
- free_dma_iso_ctx(d);
- return NULL;
- }
-
- spin_lock_init(&d->lock);
-
- DBGMSG(ohci->host->id, "Iso %s DMA: %d buffers "
- "of size %d allocated for a frame size %d, each with %d prgs",
- (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit",
- d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd);
-
- return d;
-}
-
-static void reset_ir_status(struct dma_iso_ctx *d, int n)
-{
- int i;
- d->ir_prg[n][0].status = cpu_to_le32(4);
- d->ir_prg[n][1].status = cpu_to_le32(PAGE_SIZE-4);
- for (i = 2; i < d->nb_cmd - 1; i++)
- d->ir_prg[n][i].status = cpu_to_le32(PAGE_SIZE);
- d->ir_prg[n][i].status = cpu_to_le32(d->left_size);
-}
-
-static void reprogram_dma_ir_prg(struct dma_iso_ctx *d, int n, int buffer, int flags)
-{
- struct dma_cmd *ir_prg = d->ir_prg[n];
- unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
- int i;
-
- d->buffer_prg_assignment[n] = buffer;
-
- ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
- (unsigned long)d->dma.kvirt));
- ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf + 4) - (unsigned long)d->dma.kvirt));
-
- for (i=2;i<d->nb_cmd-1;i++) {
- ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf+(i-1)*PAGE_SIZE) -
- (unsigned long)d->dma.kvirt));
- }
-
- ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
- ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf+(i-1)*PAGE_SIZE) - (unsigned long)d->dma.kvirt));
-}
-
-static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags)
-{
- struct dma_cmd *ir_prg = d->ir_prg[n];
- struct dma_prog_region *ir_reg = &d->prg_reg[n];
- unsigned long buf = (unsigned long)d->dma.kvirt;
- int i;
-
- /* the first descriptor will read only 4 bytes */
- ir_prg[0].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_BRANCH | 4);
-
- /* set the sync flag */
- if (flags & VIDEO1394_SYNC_FRAMES)
- ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT);
-
- ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
- (unsigned long)d->dma.kvirt));
- ir_prg[0].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
- 1 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
-
- /* If there is *not* only one DMA page per frame (hence, d->nb_cmd==2) */
- if (d->nb_cmd > 2) {
- /* The second descriptor will read PAGE_SIZE-4 bytes */
- ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_BRANCH | (PAGE_SIZE-4));
- ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf + 4) -
- (unsigned long)d->dma.kvirt));
- ir_prg[1].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
- 2 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
-
- for (i = 2; i < d->nb_cmd - 1; i++) {
- ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_BRANCH | PAGE_SIZE);
- ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf+(i-1)*PAGE_SIZE) -
- (unsigned long)d->dma.kvirt));
-
- ir_prg[i].branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
- (i + 1) * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
- }
-
- /* The last descriptor will generate an interrupt */
- ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
- ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf+(i-1)*PAGE_SIZE) -
- (unsigned long)d->dma.kvirt));
- } else {
- /* Only one DMA page is used. Read d->left_size immediately and */
- /* generate an interrupt as this is also the last page. */
- ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_IRQ | DMA_CTL_BRANCH | (d->left_size-4));
- ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf + 4) - (unsigned long)d->dma.kvirt));
- }
-}
-
-static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags)
-{
- struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
- int i;
-
- d->flags = flags;
-
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
- for (i=0;i<d->num_desc;i++) {
- initialize_dma_ir_prg(d, i, flags);
- reset_ir_status(d, i);
- }
-
- /* reset the ctrl register */
- reg_write(ohci, d->ctrlClear, 0xf0000000);
-
- /* Set bufferFill */
- reg_write(ohci, d->ctrlSet, 0x80000000);
-
- /* Set isoch header */
- if (flags & VIDEO1394_INCLUDE_ISO_HEADERS)
- reg_write(ohci, d->ctrlSet, 0x40000000);
-
- /* Set the context match register to match on all tags,
- sync for sync tag, and listen to d->channel */
- reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel);
-
- /* Set up isoRecvIntMask to generate interrupts */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<<d->ctx);
-}
-
-/* find which context is listening to this channel */
-static struct dma_iso_ctx *
-find_ctx(struct list_head *list, int type, int channel)
-{
- struct dma_iso_ctx *ctx;
-
- list_for_each_entry(ctx, list, link) {
- if (ctx->type == type && ctx->channel == channel)
- return ctx;
- }
-
- return NULL;
-}
-
-static void wakeup_dma_ir_ctx(unsigned long l)
-{
- struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
- int i;
-
- spin_lock(&d->lock);
-
- for (i = 0; i < d->num_desc; i++) {
- if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
- reset_ir_status(d, i);
- d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
- do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]);
- dma_region_sync_for_cpu(&d->dma,
- d->buffer_prg_assignment[i] * d->buf_size,
- d->buf_size);
- }
- }
-
- spin_unlock(&d->lock);
-
- if (waitqueue_active(&d->waitq))
- wake_up_interruptible(&d->waitq);
-}
-
-static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d,
- int n)
-{
- unsigned char* buf = d->dma.kvirt + n * d->buf_size;
- u32 cycleTimer;
- u32 timeStamp;
-
- if (n == -1) {
- return;
- }
-
- cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-
- timeStamp = ((cycleTimer & 0x0fff) + d->syt_offset); /* 11059 = 450 us */
- timeStamp = (timeStamp % 3072 + ((timeStamp / 3072) << 12)
- + (cycleTimer & 0xf000)) & 0xffff;
-
- buf[6] = timeStamp >> 8;
- buf[7] = timeStamp & 0xff;
-
- /* if first packet is empty packet, then put timestamp into the next full one too */
- if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
- buf += d->packet_size;
- buf[6] = timeStamp >> 8;
- buf[7] = timeStamp & 0xff;
- }
-
- /* do the next buffer frame too in case of irq latency */
- n = d->next_buffer[n];
- if (n == -1) {
- return;
- }
- buf = d->dma.kvirt + n * d->buf_size;
-
- timeStamp += (d->last_used_cmd[n] << 12) & 0xffff;
-
- buf[6] = timeStamp >> 8;
- buf[7] = timeStamp & 0xff;
-
- /* if first packet is empty packet, then put timestamp into the next full one too */
- if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
- buf += d->packet_size;
- buf[6] = timeStamp >> 8;
- buf[7] = timeStamp & 0xff;
- }
-
-#if 0
- printk("curr: %d, next: %d, cycleTimer: %08x timeStamp: %08x\n",
- curr, n, cycleTimer, timeStamp);
-#endif
-}
-
-static void wakeup_dma_it_ctx(unsigned long l)
-{
- struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
- struct ti_ohci *ohci = d->ohci;
- int i;
-
- spin_lock(&d->lock);
-
- for (i = 0; i < d->num_desc; i++) {
- if (d->it_prg[i][d->last_used_cmd[i]].end.status &
- cpu_to_le32(0xFFFF0000)) {
- int next = d->next_buffer[i];
- put_timestamp(ohci, d, next);
- d->it_prg[i][d->last_used_cmd[i]].end.status = 0;
- d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
- }
- }
-
- spin_unlock(&d->lock);
-
- if (waitqueue_active(&d->waitq))
- wake_up_interruptible(&d->waitq);
-}
-
-static void reprogram_dma_it_prg(struct dma_iso_ctx *d, int n, int buffer)
-{
- struct it_dma_prg *it_prg = d->it_prg[n];
- unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
- int i;
-
- d->buffer_prg_assignment[n] = buffer;
- for (i=0;i<d->nb_cmd;i++) {
- it_prg[i].end.address =
- cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf+i*d->packet_size) - (unsigned long)d->dma.kvirt));
- }
-}
-
-static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag)
-{
- struct it_dma_prg *it_prg = d->it_prg[n];
- struct dma_prog_region *it_reg = &d->prg_reg[n];
- unsigned long buf = (unsigned long)d->dma.kvirt;
- int i;
- d->last_used_cmd[n] = d->nb_cmd - 1;
- for (i=0;i<d->nb_cmd;i++) {
-
- it_prg[i].begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 8) ;
- it_prg[i].begin.address = 0;
-
- it_prg[i].begin.status = 0;
-
- it_prg[i].data[0] = cpu_to_le32(
- (IEEE1394_SPEED_100 << 16)
- | (/* tag */ 1 << 14)
- | (d->channel << 8)
- | (TCODE_ISO_DATA << 4));
- if (i==0) it_prg[i].data[0] |= cpu_to_le32(sync_tag);
- it_prg[i].data[1] = cpu_to_le32(d->packet_size << 16);
- it_prg[i].data[2] = 0;
- it_prg[i].data[3] = 0;
-
- it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_BRANCH);
- it_prg[i].end.address =
- cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) -
- (unsigned long)d->dma.kvirt));
-
- if (i<d->nb_cmd-1) {
- it_prg[i].end.control |= cpu_to_le32(d->packet_size);
- it_prg[i].begin.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
- sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
- it_prg[i].end.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
- sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
- } else {
- /* the last prg generates an interrupt */
- it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE |
- DMA_CTL_IRQ | d->left_size);
- /* the last prg doesn't branch */
- it_prg[i].begin.branchAddress = 0;
- it_prg[i].end.branchAddress = 0;
- }
- it_prg[i].end.status = 0;
- }
-}
-
-static void initialize_dma_it_prg_var_packet_queue(
- struct dma_iso_ctx *d, int n, unsigned int * packet_sizes,
- struct ti_ohci *ohci)
-{
- struct it_dma_prg *it_prg = d->it_prg[n];
- struct dma_prog_region *it_reg = &d->prg_reg[n];
- int i;
-
-#if 0
- if (n != -1) {
- put_timestamp(ohci, d, n);
- }
-#endif
- d->last_used_cmd[n] = d->nb_cmd - 1;
-
- for (i = 0; i < d->nb_cmd; i++) {
- unsigned int size;
- if (packet_sizes[i] > d->packet_size) {
- size = d->packet_size;
- } else {
- size = packet_sizes[i];
- }
- it_prg[i].data[1] = cpu_to_le32(size << 16);
- it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH);
-
- if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) {
- it_prg[i].end.control |= cpu_to_le32(size);
- it_prg[i].begin.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
- sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
- it_prg[i].end.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
- sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
- } else {
- /* the last prg generates an interrupt */
- it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE |
- DMA_CTL_IRQ | size);
- /* the last prg doesn't branch */
- it_prg[i].begin.branchAddress = 0;
- it_prg[i].end.branchAddress = 0;
- d->last_used_cmd[n] = i;
- break;
- }
- }
-}
-
-static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag,
- unsigned int syt_offset, int flags)
-{
- struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
- int i;
-
- d->flags = flags;
- d->syt_offset = (syt_offset == 0 ? 11000 : syt_offset);
-
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
- for (i=0;i<d->num_desc;i++)
- initialize_dma_it_prg(d, i, sync_tag);
-
- /* Set up isoRecvIntMask to generate interrupts */
- reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
-}
-
-static inline unsigned video1394_buffer_state(struct dma_iso_ctx *d,
- unsigned int buffer)
-{
- unsigned long flags;
- unsigned int ret;
- spin_lock_irqsave(&d->lock, flags);
- ret = d->buffer_status[buffer];
- spin_unlock_irqrestore(&d->lock, flags);
- return ret;
-}
-
-static long video1394_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct file_ctx *ctx = file->private_data;
- struct ti_ohci *ohci = ctx->ohci;
- unsigned long flags;
- void __user *argp = (void __user *)arg;
-
- switch(cmd)
- {
- case VIDEO1394_IOC_LISTEN_CHANNEL:
- case VIDEO1394_IOC_TALK_CHANNEL:
- {
- struct video1394_mmap v;
- u64 mask;
- struct dma_iso_ctx *d;
- int i;
-
- if (copy_from_user(&v, argp, sizeof(v)))
- return -EFAULT;
-
- /* if channel < 0, find lowest available one */
- if (v.channel < 0) {
- mask = (u64)0x1;
- for (i=0; ; i++) {
- if (i == ISO_CHANNELS) {
- PRINT(KERN_ERR, ohci->host->id,
- "No free channel found");
- return -EAGAIN;
- }
- if (!(ohci->ISO_channel_usage & mask)) {
- v.channel = i;
- PRINT(KERN_INFO, ohci->host->id, "Found free channel %d", i);
- break;
- }
- mask = mask << 1;
- }
- } else if (v.channel >= ISO_CHANNELS) {
- PRINT(KERN_ERR, ohci->host->id,
- "Iso channel %d out of bounds", v.channel);
- return -EINVAL;
- } else {
- mask = (u64)0x1<<v.channel;
- }
- DBGMSG(ohci->host->id, "mask: %08X%08X usage: %08X%08X\n",
- (u32)(mask>>32),(u32)(mask&0xffffffff),
- (u32)(ohci->ISO_channel_usage>>32),
- (u32)(ohci->ISO_channel_usage&0xffffffff));
- if (ohci->ISO_channel_usage & mask) {
- PRINT(KERN_ERR, ohci->host->id,
- "Channel %d is already taken", v.channel);
- return -EBUSY;
- }
-
- if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) {
- PRINT(KERN_ERR, ohci->host->id,
- "Invalid %d length buffer requested",v.buf_size);
- return -EINVAL;
- }
-
- if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) {
- PRINT(KERN_ERR, ohci->host->id,
- "Invalid %d buffers requested",v.nb_buffers);
- return -EINVAL;
- }
-
- if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {
- PRINT(KERN_ERR, ohci->host->id,
- "%d buffers of size %d bytes is too big",
- v.nb_buffers, v.buf_size);
- return -EINVAL;
- }
-
- if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) {
- d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE,
- v.nb_buffers + 1, v.buf_size,
- v.channel, 0);
-
- if (d == NULL) {
- PRINT(KERN_ERR, ohci->host->id,
- "Couldn't allocate ir context");
- return -EAGAIN;
- }
- initialize_dma_ir_ctx(d, v.sync_tag, v.flags);
-
- ctx->current_ctx = d;
-
- v.buf_size = d->buf_size;
- list_add_tail(&d->link, &ctx->context_list);
-
- DBGMSG(ohci->host->id,
- "iso context %d listen on channel %d",
- d->ctx, v.channel);
- }
- else {
- d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT,
- v.nb_buffers + 1, v.buf_size,
- v.channel, v.packet_size);
-
- if (d == NULL) {
- PRINT(KERN_ERR, ohci->host->id,
- "Couldn't allocate it context");
- return -EAGAIN;
- }
- initialize_dma_it_ctx(d, v.sync_tag,
- v.syt_offset, v.flags);
-
- ctx->current_ctx = d;
-
- v.buf_size = d->buf_size;
-
- list_add_tail(&d->link, &ctx->context_list);
-
- DBGMSG(ohci->host->id,
- "Iso context %d talk on channel %d", d->ctx,
- v.channel);
- }
-
- if (copy_to_user(argp, &v, sizeof(v))) {
- /* FIXME : free allocated dma resources */
- return -EFAULT;
- }
-
- ohci->ISO_channel_usage |= mask;
-
- return 0;
- }
- case VIDEO1394_IOC_UNLISTEN_CHANNEL:
- case VIDEO1394_IOC_UNTALK_CHANNEL:
- {
- int channel;
- u64 mask;
- struct dma_iso_ctx *d;
-
- if (copy_from_user(&channel, argp, sizeof(int)))
- return -EFAULT;
-
- if (channel < 0 || channel >= ISO_CHANNELS) {
- PRINT(KERN_ERR, ohci->host->id,
- "Iso channel %d out of bound", channel);
- return -EINVAL;
- }
- mask = (u64)0x1<<channel;
- if (!(ohci->ISO_channel_usage & mask)) {
- PRINT(KERN_ERR, ohci->host->id,
- "Channel %d is not being used", channel);
- return -ESRCH;
- }
-
- /* Mark this channel as unused */
- ohci->ISO_channel_usage &= ~mask;
-
- if (cmd == VIDEO1394_IOC_UNLISTEN_CHANNEL)
- d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel);
- else
- d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel);
-
- if (d == NULL) return -ESRCH;
- DBGMSG(ohci->host->id, "Iso context %d "
- "stop talking on channel %d", d->ctx, channel);
- free_dma_iso_ctx(d);
-
- return 0;
- }
- case VIDEO1394_IOC_LISTEN_QUEUE_BUFFER:
- {
- struct video1394_wait v;
- struct dma_iso_ctx *d;
- int next_prg;
-
- if (unlikely(copy_from_user(&v, argp, sizeof(v))))
- return -EFAULT;
-
- d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
- if (unlikely(d == NULL))
- return -EFAULT;
-
- if (unlikely(v.buffer >= d->num_desc - 1)) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d out of range",v.buffer);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&d->lock,flags);
-
- if (unlikely(d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED)) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d is already used",v.buffer);
- spin_unlock_irqrestore(&d->lock,flags);
- return -EBUSY;
- }
-
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
-
- next_prg = (d->last_buffer + 1) % d->num_desc;
- if (d->last_buffer>=0)
- d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0)
- & 0xfffffff0) | 0x1);
-
- d->last_buffer = next_prg;
- reprogram_dma_ir_prg(d, d->last_buffer, v.buffer, d->flags);
-
- d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0;
-
- spin_unlock_irqrestore(&d->lock,flags);
-
- if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
- {
- DBGMSG(ohci->host->id, "Starting iso DMA ctx=%d",d->ctx);
-
- /* Tell the controller where the first program is */
- reg_write(ohci, d->cmdPtr,
- dma_prog_region_offset_to_bus(&d->prg_reg[d->last_buffer], 0) | 0x1);
-
- /* Run IR context */
- reg_write(ohci, d->ctrlSet, 0x8000);
- }
- else {
- /* Wake up dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
- DBGMSG(ohci->host->id,
- "Waking up iso dma ctx=%d", d->ctx);
- reg_write(ohci, d->ctrlSet, 0x1000);
- }
- }
- return 0;
-
- }
- case VIDEO1394_IOC_LISTEN_WAIT_BUFFER:
- case VIDEO1394_IOC_LISTEN_POLL_BUFFER:
- {
- struct video1394_wait v;
- struct dma_iso_ctx *d;
- int i = 0;
-
- if (unlikely(copy_from_user(&v, argp, sizeof(v))))
- return -EFAULT;
-
- d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
- if (unlikely(d == NULL))
- return -EFAULT;
-
- if (unlikely(v.buffer > d->num_desc - 1)) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d out of range",v.buffer);
- return -EINVAL;
- }
-
- /*
- * I change the way it works so that it returns
- * the last received frame.
- */
- spin_lock_irqsave(&d->lock, flags);
- switch(d->buffer_status[v.buffer]) {
- case VIDEO1394_BUFFER_READY:
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
- break;
- case VIDEO1394_BUFFER_QUEUED:
- if (cmd == VIDEO1394_IOC_LISTEN_POLL_BUFFER) {
- /* for polling, return error code EINTR */
- spin_unlock_irqrestore(&d->lock, flags);
- return -EINTR;
- }
-
- spin_unlock_irqrestore(&d->lock, flags);
- wait_event_interruptible(d->waitq,
- video1394_buffer_state(d, v.buffer) ==
- VIDEO1394_BUFFER_READY);
- if (signal_pending(current))
- return -EINTR;
- spin_lock_irqsave(&d->lock, flags);
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
- break;
- default:
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d is not queued",v.buffer);
- spin_unlock_irqrestore(&d->lock, flags);
- return -ESRCH;
- }
-
- /* set time of buffer */
- v.filltime = d->buffer_time[v.buffer];
-
- /*
- * Look ahead to see how many more buffers have been received
- */
- i=0;
- while (d->buffer_status[(v.buffer+1)%(d->num_desc - 1)]==
- VIDEO1394_BUFFER_READY) {
- v.buffer=(v.buffer+1)%(d->num_desc - 1);
- i++;
- }
- spin_unlock_irqrestore(&d->lock, flags);
-
- v.buffer=i;
- if (unlikely(copy_to_user(argp, &v, sizeof(v))))
- return -EFAULT;
-
- return 0;
- }
- case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
- {
- struct video1394_wait v;
- unsigned int *psizes = NULL;
- struct dma_iso_ctx *d;
- int next_prg;
-
- if (copy_from_user(&v, argp, sizeof(v)))
- return -EFAULT;
-
- d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
- if (d == NULL) return -EFAULT;
-
- if (v.buffer >= d->num_desc - 1) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d out of range",v.buffer);
- return -EINVAL;
- }
-
- if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
- int buf_size = d->nb_cmd * sizeof(*psizes);
- struct video1394_queue_variable __user *p = argp;
- unsigned int __user *qv;
-
- if (get_user(qv, &p->packet_sizes))
- return -EFAULT;
-
- psizes = memdup_user(qv, buf_size);
- if (IS_ERR(psizes))
- return PTR_ERR(psizes);
- }
-
- spin_lock_irqsave(&d->lock,flags);
-
- /* last_buffer is last_prg */
- next_prg = (d->last_buffer + 1) % d->num_desc;
- if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d is already used",v.buffer);
- spin_unlock_irqrestore(&d->lock,flags);
- kfree(psizes);
- return -EBUSY;
- }
-
- if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
- initialize_dma_it_prg_var_packet_queue(
- d, next_prg, psizes, ohci);
- }
-
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
-
- if (d->last_buffer >= 0) {
- d->it_prg[d->last_buffer]
- [ d->last_used_cmd[d->last_buffer] ].end.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
- 0) & 0xfffffff0) | 0x3);
-
- d->it_prg[d->last_buffer]
- [ d->last_used_cmd[d->last_buffer] ].begin.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
- 0) & 0xfffffff0) | 0x3);
- d->next_buffer[d->last_buffer] = (v.buffer + 1) % (d->num_desc - 1);
- }
- d->last_buffer = next_prg;
- reprogram_dma_it_prg(d, d->last_buffer, v.buffer);
- d->next_buffer[d->last_buffer] = -1;
-
- d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0;
-
- spin_unlock_irqrestore(&d->lock,flags);
-
- if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
- {
- DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d",
- d->ctx);
- put_timestamp(ohci, d, d->last_buffer);
- dma_region_sync_for_device(&d->dma,
- v.buffer * d->buf_size, d->buf_size);
-
- /* Tell the controller where the first program is */
- reg_write(ohci, d->cmdPtr,
- dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | 0x3);
-
- /* Run IT context */
- reg_write(ohci, d->ctrlSet, 0x8000);
- }
- else {
- /* Wake up dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
- DBGMSG(ohci->host->id,
- "Waking up iso transmit dma ctx=%d",
- d->ctx);
- put_timestamp(ohci, d, d->last_buffer);
- dma_region_sync_for_device(&d->dma,
- v.buffer * d->buf_size, d->buf_size);
-
- reg_write(ohci, d->ctrlSet, 0x1000);
- }
- }
-
- kfree(psizes);
- return 0;
-
- }
- case VIDEO1394_IOC_TALK_WAIT_BUFFER:
- {
- struct video1394_wait v;
- struct dma_iso_ctx *d;
-
- if (copy_from_user(&v, argp, sizeof(v)))
- return -EFAULT;
-
- d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
- if (d == NULL) return -EFAULT;
-
- if (v.buffer >= d->num_desc - 1) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d out of range",v.buffer);
- return -EINVAL;
- }
-
- switch(d->buffer_status[v.buffer]) {
- case VIDEO1394_BUFFER_READY:
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
- return 0;
- case VIDEO1394_BUFFER_QUEUED:
- wait_event_interruptible(d->waitq,
- (d->buffer_status[v.buffer] == VIDEO1394_BUFFER_READY));
- if (signal_pending(current))
- return -EINTR;
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
- return 0;
- default:
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d is not queued",v.buffer);
- return -ESRCH;
- }
- }
- default:
- return -ENOTTY;
- }
-}
-
-/*
- * This maps the vmalloced and reserved buffer to user space.
- *
- * FIXME:
- * - PAGE_READONLY should suffice!?
- * - remap_pfn_range is kind of inefficient for page by page remapping.
- * But e.g. pte_alloc() does not work in modules ... :-(
- */
-
-static int video1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct file_ctx *ctx = file->private_data;
-
- if (ctx->current_ctx == NULL) {
- PRINT(KERN_ERR, ctx->ohci->host->id,
- "Current iso context not set");
- return -EINVAL;
- }
-
- return dma_region_mmap(&ctx->current_ctx->dma, file, vma);
-}
-
-static unsigned int video1394_poll(struct file *file, poll_table *pt)
-{
- struct file_ctx *ctx;
- unsigned int mask = 0;
- unsigned long flags;
- struct dma_iso_ctx *d;
- int i;
-
- ctx = file->private_data;
- d = ctx->current_ctx;
- if (d == NULL) {
- PRINT(KERN_ERR, ctx->ohci->host->id,
- "Current iso context not set");
- return POLLERR;
- }
-
- poll_wait(file, &d->waitq, pt);
-
- spin_lock_irqsave(&d->lock, flags);
- for (i = 0; i < d->num_desc; i++) {
- if (d->buffer_status[i] == VIDEO1394_BUFFER_READY) {
- mask |= POLLIN | POLLRDNORM;
- break;
- }
- }
- spin_unlock_irqrestore(&d->lock, flags);
-
- return mask;
-}
-
-static int video1394_open(struct inode *inode, struct file *file)
-{
- int i = ieee1394_file_to_instance(file);
- struct ti_ohci *ohci;
- struct file_ctx *ctx;
-
- ohci = hpsb_get_hostinfo_bykey(&video1394_highlevel, i);
- if (ohci == NULL)
- return -EIO;
-
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (!ctx) {
- PRINT(KERN_ERR, ohci->host->id, "Cannot malloc file_ctx");
- return -ENOMEM;
- }
-
- ctx->ohci = ohci;
- INIT_LIST_HEAD(&ctx->context_list);
- ctx->current_ctx = NULL;
- file->private_data = ctx;
-
- return nonseekable_open(inode, file);
-}
-
-static int video1394_release(struct inode *inode, struct file *file)
-{
- struct file_ctx *ctx = file->private_data;
- struct ti_ohci *ohci = ctx->ohci;
- struct list_head *lh, *next;
- u64 mask;
-
- list_for_each_safe(lh, next, &ctx->context_list) {
- struct dma_iso_ctx *d;
- d = list_entry(lh, struct dma_iso_ctx, link);
- mask = (u64) 1 << d->channel;
-
- if (!(ohci->ISO_channel_usage & mask))
- PRINT(KERN_ERR, ohci->host->id, "On release: Channel %d "
- "is not being used", d->channel);
- else
- ohci->ISO_channel_usage &= ~mask;
- DBGMSG(ohci->host->id, "On release: Iso %s context "
- "%d stop listening on channel %d",
- d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit",
- d->ctx, d->channel);
- free_dma_iso_ctx(d);
- }
-
- kfree(ctx);
- file->private_data = NULL;
-
- return 0;
-}
-
-#ifdef CONFIG_COMPAT
-static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
-#endif
-
-static struct cdev video1394_cdev;
-static const struct file_operations video1394_fops=
-{
- .owner = THIS_MODULE,
- .unlocked_ioctl = video1394_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = video1394_compat_ioctl,
-#endif
- .poll = video1394_poll,
- .mmap = video1394_mmap,
- .open = video1394_open,
- .release = video1394_release,
- .llseek = no_llseek,
-};
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id video1394_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = CAMERA_SW_VERSION_ENTRY & 0xffffff
- },
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff
- },
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff
- },
- { }
-};
-
-MODULE_DEVICE_TABLE(ieee1394, video1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver video1394_driver = {
- .name = VIDEO1394_DRIVER_NAME,
-};
-
-
-static void video1394_add_host (struct hpsb_host *host)
-{
- struct ti_ohci *ohci;
- int minor;
-
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
-
- ohci = (struct ti_ohci *)host->hostdata;
-
- if (!hpsb_create_hostinfo(&video1394_highlevel, host, 0)) {
- PRINT(KERN_ERR, ohci->host->id, "Cannot allocate hostinfo");
- return;
- }
-
- hpsb_set_hostinfo(&video1394_highlevel, host, ohci);
- hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id);
-
- minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id;
- device_create(hpsb_protocol_class, NULL, MKDEV(IEEE1394_MAJOR, minor),
- NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
-}
-
-
-static void video1394_remove_host (struct hpsb_host *host)
-{
- struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host);
-
- if (ohci)
- device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
- return;
-}
-
-
-static struct hpsb_highlevel video1394_highlevel = {
- .name = VIDEO1394_DRIVER_NAME,
- .add_host = video1394_add_host,
- .remove_host = video1394_remove_host,
-};
-
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("driver for digital video on OHCI board");
-MODULE_SUPPORTED_DEVICE(VIDEO1394_DRIVER_NAME);
-MODULE_LICENSE("GPL");
-
-#ifdef CONFIG_COMPAT
-
-#define VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER \
- _IOW ('#', 0x12, struct video1394_wait32)
-#define VIDEO1394_IOC32_LISTEN_WAIT_BUFFER \
- _IOWR('#', 0x13, struct video1394_wait32)
-#define VIDEO1394_IOC32_TALK_WAIT_BUFFER \
- _IOW ('#', 0x17, struct video1394_wait32)
-#define VIDEO1394_IOC32_LISTEN_POLL_BUFFER \
- _IOWR('#', 0x18, struct video1394_wait32)
-
-struct video1394_wait32 {
- u32 channel;
- u32 buffer;
- struct compat_timeval filltime;
-};
-
-static int video1394_wr_wait32(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct video1394_wait32 __user *argp = (void __user *)arg;
- struct video1394_wait32 wait32;
- struct video1394_wait wait;
- mm_segment_t old_fs;
- int ret;
-
- if (copy_from_user(&wait32, argp, sizeof(wait32)))
- return -EFAULT;
-
- wait.channel = wait32.channel;
- wait.buffer = wait32.buffer;
- wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
- wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- if (cmd == VIDEO1394_IOC32_LISTEN_WAIT_BUFFER)
- ret = video1394_ioctl(file,
- VIDEO1394_IOC_LISTEN_WAIT_BUFFER,
- (unsigned long) &wait);
- else
- ret = video1394_ioctl(file,
- VIDEO1394_IOC_LISTEN_POLL_BUFFER,
- (unsigned long) &wait);
- set_fs(old_fs);
-
- if (!ret) {
- wait32.channel = wait.channel;
- wait32.buffer = wait.buffer;
- wait32.filltime.tv_sec = (int)wait.filltime.tv_sec;
- wait32.filltime.tv_usec = (int)wait.filltime.tv_usec;
-
- if (copy_to_user(argp, &wait32, sizeof(wait32)))
- ret = -EFAULT;
- }
-
- return ret;
-}
-
-static int video1394_w_wait32(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct video1394_wait32 wait32;
- struct video1394_wait wait;
- mm_segment_t old_fs;
- int ret;
-
- if (copy_from_user(&wait32, (void __user *)arg, sizeof(wait32)))
- return -EFAULT;
-
- wait.channel = wait32.channel;
- wait.buffer = wait32.buffer;
- wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
- wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- if (cmd == VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER)
- ret = video1394_ioctl(file,
- VIDEO1394_IOC_LISTEN_QUEUE_BUFFER,
- (unsigned long) &wait);
- else
- ret = video1394_ioctl(file,
- VIDEO1394_IOC_TALK_WAIT_BUFFER,
- (unsigned long) &wait);
- set_fs(old_fs);
-
- return ret;
-}
-
-static int video1394_queue_buf32(struct file *file, unsigned int cmd, unsigned long arg)
-{
- return -EFAULT; /* ??? was there before. */
-
- return video1394_ioctl(file,
- VIDEO1394_IOC_TALK_QUEUE_BUFFER, arg);
-}
-
-static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
-{
- switch (cmd) {
- case VIDEO1394_IOC_LISTEN_CHANNEL:
- case VIDEO1394_IOC_UNLISTEN_CHANNEL:
- case VIDEO1394_IOC_TALK_CHANNEL:
- case VIDEO1394_IOC_UNTALK_CHANNEL:
- return video1394_ioctl(f, cmd, arg);
-
- case VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER:
- return video1394_w_wait32(f, cmd, arg);
- case VIDEO1394_IOC32_LISTEN_WAIT_BUFFER:
- return video1394_wr_wait32(f, cmd, arg);
- case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
- return video1394_queue_buf32(f, cmd, arg);
- case VIDEO1394_IOC32_TALK_WAIT_BUFFER:
- return video1394_w_wait32(f, cmd, arg);
- case VIDEO1394_IOC32_LISTEN_POLL_BUFFER:
- return video1394_wr_wait32(f, cmd, arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-#endif /* CONFIG_COMPAT */
-
-static void __exit video1394_exit_module (void)
-{
- hpsb_unregister_protocol(&video1394_driver);
- hpsb_unregister_highlevel(&video1394_highlevel);
- cdev_del(&video1394_cdev);
- PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
-}
-
-static int __init video1394_init_module (void)
-{
- int ret;
-
- hpsb_init_highlevel(&video1394_highlevel);
-
- cdev_init(&video1394_cdev, &video1394_fops);
- video1394_cdev.owner = THIS_MODULE;
- ret = cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16);
- if (ret) {
- PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
- return ret;
- }
-
- hpsb_register_highlevel(&video1394_highlevel);
-
- ret = hpsb_register_protocol(&video1394_driver);
- if (ret) {
- PRINT_G(KERN_ERR, "video1394: failed to register protocol");
- hpsb_unregister_highlevel(&video1394_highlevel);
- cdev_del(&video1394_cdev);
- return ret;
- }
-
- PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
- return 0;
-}
-
-
-module_init(video1394_init_module);
-module_exit(video1394_exit_module);
diff --git a/drivers/ieee1394/video1394.h b/drivers/ieee1394/video1394.h
deleted file mode 100644
index 9a89d9cc3c85..000000000000
--- a/drivers/ieee1394/video1394.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * video1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _VIDEO_1394_H
-#define _VIDEO_1394_H
-
-#include "ieee1394-ioctl.h"
-
-#define VIDEO1394_DRIVER_NAME "video1394"
-
-#define VIDEO1394_MAX_SIZE 0x4000000
-
-enum {
- VIDEO1394_BUFFER_FREE = 0,
- VIDEO1394_BUFFER_QUEUED,
- VIDEO1394_BUFFER_READY
-};
-
-#define VIDEO1394_SYNC_FRAMES 0x00000001
-#define VIDEO1394_INCLUDE_ISO_HEADERS 0x00000002
-#define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004
-
-struct video1394_mmap {
- int channel; /* -1 to find an open channel in LISTEN/TALK */
- unsigned int sync_tag;
- unsigned int nb_buffers;
- unsigned int buf_size;
- unsigned int packet_size; /* For VARIABLE_PACKET_SIZE:
- Maximum packet size */
- unsigned int fps;
- unsigned int syt_offset;
- unsigned int flags;
-};
-
-/* For TALK_QUEUE_BUFFER with VIDEO1394_VARIABLE_PACKET_SIZE use */
-struct video1394_queue_variable {
- unsigned int channel;
- unsigned int buffer;
- unsigned int __user * packet_sizes; /* Buffer of size:
- buf_size / packet_size */
-};
-
-struct video1394_wait {
- unsigned int channel;
- unsigned int buffer;
- struct timeval filltime; /* time of buffer full */
-};
-
-
-#endif
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 535fea4fe67f..e3f7fc6f9565 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -534,6 +534,80 @@ static int handle_eviocgbit(struct input_dev *dev,
}
#undef OLD_KEY_MAX
+static int evdev_handle_get_keycode(struct input_dev *dev,
+ void __user *p, size_t size)
+{
+ struct input_keymap_entry ke;
+ int error;
+
+ memset(&ke, 0, sizeof(ke));
+
+ if (size == sizeof(unsigned int[2])) {
+ /* legacy case */
+ int __user *ip = (int __user *)p;
+
+ if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
+ return -EFAULT;
+
+ ke.len = sizeof(unsigned int);
+ ke.flags = 0;
+
+ error = input_get_keycode(dev, &ke);
+ if (error)
+ return error;
+
+ if (put_user(ke.keycode, ip + 1))
+ return -EFAULT;
+
+ } else {
+ size = min(size, sizeof(ke));
+
+ if (copy_from_user(&ke, p, size))
+ return -EFAULT;
+
+ error = input_get_keycode(dev, &ke);
+ if (error)
+ return error;
+
+ if (copy_to_user(p, &ke, size))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int evdev_handle_set_keycode(struct input_dev *dev,
+ void __user *p, size_t size)
+{
+ struct input_keymap_entry ke;
+
+ memset(&ke, 0, sizeof(ke));
+
+ if (size == sizeof(unsigned int[2])) {
+ /* legacy case */
+ int __user *ip = (int __user *)p;
+
+ if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
+ return -EFAULT;
+
+ if (get_user(ke.keycode, ip + 1))
+ return -EFAULT;
+
+ ke.len = sizeof(unsigned int);
+ ke.flags = 0;
+
+ } else {
+ size = min(size, sizeof(ke));
+
+ if (copy_from_user(&ke, p, size))
+ return -EFAULT;
+
+ if (ke.len > sizeof(ke.scancode))
+ return -EINVAL;
+ }
+
+ return input_set_keycode(dev, &ke);
+}
+
static long evdev_do_ioctl(struct file *file, unsigned int cmd,
void __user *p, int compat_mode)
{
@@ -580,25 +654,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return 0;
- case EVIOCGKEYCODE:
- if (get_user(t, ip))
- return -EFAULT;
-
- error = input_get_keycode(dev, t, &v);
- if (error)
- return error;
-
- if (put_user(v, ip + 1))
- return -EFAULT;
-
- return 0;
-
- case EVIOCSKEYCODE:
- if (get_user(t, ip) || get_user(v, ip + 1))
- return -EFAULT;
-
- return input_set_keycode(dev, t, v);
-
case EVIOCRMFF:
return input_ff_erase(dev, (int)(unsigned long) p, file);
@@ -620,7 +675,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
/* Now check variable-length commands */
#define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
-
switch (EVIOC_MASK_SIZE(cmd)) {
case EVIOCGKEY(0):
@@ -654,6 +708,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
return error;
+
+ case EVIOC_MASK_SIZE(EVIOCGKEYCODE):
+ return evdev_handle_get_keycode(dev, p, size);
+
+ case EVIOC_MASK_SIZE(EVIOCSKEYCODE):
+ return evdev_handle_set_keycode(dev, p, size);
}
/* Multi-number variable-length handlers */
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
index 7392992da424..422aa0a6b77f 100644
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -59,44 +59,52 @@ MODULE_DEVICE_TABLE(pci, emu_tbl);
static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- int ioport, iolen;
struct emu *emu;
struct gameport *port;
-
- if (pci_enable_device(pdev))
- return -EBUSY;
-
- ioport = pci_resource_start(pdev, 0);
- iolen = pci_resource_len(pdev, 0);
-
- if (!request_region(ioport, iolen, "emu10k1-gp"))
- return -EBUSY;
+ int error;
emu = kzalloc(sizeof(struct emu), GFP_KERNEL);
port = gameport_allocate_port();
if (!emu || !port) {
printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
- release_region(ioport, iolen);
- kfree(emu);
- gameport_free_port(port);
- return -ENOMEM;
+ error = -ENOMEM;
+ goto err_out_free;
}
- emu->io = ioport;
- emu->size = iolen;
+ error = pci_enable_device(pdev);
+ if (error)
+ goto err_out_free;
+
+ emu->io = pci_resource_start(pdev, 0);
+ emu->size = pci_resource_len(pdev, 0);
+
emu->dev = pdev;
emu->gameport = port;
gameport_set_name(port, "EMU10K1");
gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
port->dev.parent = &pdev->dev;
- port->io = ioport;
+ port->io = emu->io;
+
+ if (!request_region(emu->io, emu->size, "emu10k1-gp")) {
+ printk(KERN_ERR "emu10k1-gp: unable to grab region 0x%x-0x%x\n",
+ emu->io, emu->io + emu->size - 1);
+ error = -EBUSY;
+ goto err_out_disable_dev;
+ }
pci_set_drvdata(pdev, emu);
gameport_register_port(port);
return 0;
+
+ err_out_disable_dev:
+ pci_disable_device(pdev);
+ err_out_free:
+ gameport_free_port(port);
+ kfree(emu);
+ return error;
}
static void __devexit emu_remove(struct pci_dev *pdev)
@@ -106,6 +114,8 @@ static void __devexit emu_remove(struct pci_dev *pdev)
gameport_unregister_port(emu->gameport);
release_region(emu->io, emu->size);
kfree(emu);
+
+ pci_disable_device(pdev);
}
static struct pci_driver emu_driver = {
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index 14d3f3e208a2..a3b70ff21018 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -133,11 +133,11 @@ static void __devexit fm801_gp_remove(struct pci_dev *pci)
{
struct fm801_gp *gp = pci_get_drvdata(pci);
- if (gp) {
- gameport_unregister_port(gp->gameport);
- release_resource(gp->res_port);
- kfree(gp);
- }
+ gameport_unregister_port(gp->gameport);
+ release_resource(gp->res_port);
+ kfree(gp);
+
+ pci_disable_device(pci);
}
static const struct pci_device_id fm801_gp_id_table[] = {
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 7919c2537225..d092ef9291da 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -171,7 +171,7 @@ static int input_handle_abs_event(struct input_dev *dev,
if (code == ABS_MT_SLOT) {
/*
* "Stage" the event; we'll flush it later, when we
- * get actiual touch data.
+ * get actual touch data.
*/
if (*pval >= 0 && *pval < dev->mtsize)
dev->slot = *pval;
@@ -188,7 +188,7 @@ static int input_handle_abs_event(struct input_dev *dev,
pold = &mtslot->abs[code - ABS_MT_FIRST];
} else {
/*
- * Bypass filtering for multitouch events when
+ * Bypass filtering for multi-touch events when
* not employing slots.
*/
pold = NULL;
@@ -634,78 +634,141 @@ static void input_disconnect_device(struct input_dev *dev)
spin_unlock_irq(&dev->event_lock);
}
-static int input_fetch_keycode(struct input_dev *dev, int scancode)
+/**
+ * input_scancode_to_scalar() - converts scancode in &struct input_keymap_entry
+ * @ke: keymap entry containing scancode to be converted.
+ * @scancode: pointer to the location where converted scancode should
+ * be stored.
+ *
+ * This function is used to convert scancode stored in &struct keymap_entry
+ * into scalar form understood by legacy keymap handling methods. These
+ * methods expect scancodes to be represented as 'unsigned int'.
+ */
+int input_scancode_to_scalar(const struct input_keymap_entry *ke,
+ unsigned int *scancode)
+{
+ switch (ke->len) {
+ case 1:
+ *scancode = *((u8 *)ke->scancode);
+ break;
+
+ case 2:
+ *scancode = *((u16 *)ke->scancode);
+ break;
+
+ case 4:
+ *scancode = *((u32 *)ke->scancode);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(input_scancode_to_scalar);
+
+/*
+ * Those routines handle the default case where no [gs]etkeycode() is
+ * defined. In this case, an array indexed by the scancode is used.
+ */
+
+static unsigned int input_fetch_keycode(struct input_dev *dev,
+ unsigned int index)
{
switch (dev->keycodesize) {
- case 1:
- return ((u8 *)dev->keycode)[scancode];
+ case 1:
+ return ((u8 *)dev->keycode)[index];
- case 2:
- return ((u16 *)dev->keycode)[scancode];
+ case 2:
+ return ((u16 *)dev->keycode)[index];
- default:
- return ((u32 *)dev->keycode)[scancode];
+ default:
+ return ((u32 *)dev->keycode)[index];
}
}
static int input_default_getkeycode(struct input_dev *dev,
- unsigned int scancode,
- unsigned int *keycode)
+ struct input_keymap_entry *ke)
{
+ unsigned int index;
+ int error;
+
if (!dev->keycodesize)
return -EINVAL;
- if (scancode >= dev->keycodemax)
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+ index = ke->index;
+ else {
+ error = input_scancode_to_scalar(ke, &index);
+ if (error)
+ return error;
+ }
+
+ if (index >= dev->keycodemax)
return -EINVAL;
- *keycode = input_fetch_keycode(dev, scancode);
+ ke->keycode = input_fetch_keycode(dev, index);
+ ke->index = index;
+ ke->len = sizeof(index);
+ memcpy(ke->scancode, &index, sizeof(index));
return 0;
}
static int input_default_setkeycode(struct input_dev *dev,
- unsigned int scancode,
- unsigned int keycode)
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
- int old_keycode;
+ unsigned int index;
+ int error;
int i;
- if (scancode >= dev->keycodemax)
+ if (!dev->keycodesize)
return -EINVAL;
- if (!dev->keycodesize)
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ } else {
+ error = input_scancode_to_scalar(ke, &index);
+ if (error)
+ return error;
+ }
+
+ if (index >= dev->keycodemax)
return -EINVAL;
- if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
+ if (dev->keycodesize < sizeof(dev->keycode) &&
+ (ke->keycode >> (dev->keycodesize * 8)))
return -EINVAL;
switch (dev->keycodesize) {
case 1: {
u8 *k = (u8 *)dev->keycode;
- old_keycode = k[scancode];
- k[scancode] = keycode;
+ *old_keycode = k[index];
+ k[index] = ke->keycode;
break;
}
case 2: {
u16 *k = (u16 *)dev->keycode;
- old_keycode = k[scancode];
- k[scancode] = keycode;
+ *old_keycode = k[index];
+ k[index] = ke->keycode;
break;
}
default: {
u32 *k = (u32 *)dev->keycode;
- old_keycode = k[scancode];
- k[scancode] = keycode;
+ *old_keycode = k[index];
+ k[index] = ke->keycode;
break;
}
}
- __clear_bit(old_keycode, dev->keybit);
- __set_bit(keycode, dev->keybit);
+ __clear_bit(*old_keycode, dev->keybit);
+ __set_bit(ke->keycode, dev->keybit);
for (i = 0; i < dev->keycodemax; i++) {
- if (input_fetch_keycode(dev, i) == old_keycode) {
- __set_bit(old_keycode, dev->keybit);
+ if (input_fetch_keycode(dev, i) == *old_keycode) {
+ __set_bit(*old_keycode, dev->keybit);
break; /* Setting the bit twice is useless, so break */
}
}
@@ -716,53 +779,86 @@ static int input_default_setkeycode(struct input_dev *dev,
/**
* input_get_keycode - retrieve keycode currently mapped to a given scancode
* @dev: input device which keymap is being queried
- * @scancode: scancode (or its equivalent for device in question) for which
- * keycode is needed
- * @keycode: result
+ * @ke: keymap entry
*
* This function should be called by anyone interested in retrieving current
- * keymap. Presently keyboard and evdev handlers use it.
+ * keymap. Presently evdev handlers use it.
*/
-int input_get_keycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
+int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke)
{
unsigned long flags;
int retval;
spin_lock_irqsave(&dev->event_lock, flags);
- retval = dev->getkeycode(dev, scancode, keycode);
- spin_unlock_irqrestore(&dev->event_lock, flags);
+ if (dev->getkeycode) {
+ /*
+ * Support for legacy drivers, that don't implement the new
+ * ioctls
+ */
+ u32 scancode = ke->index;
+
+ memcpy(ke->scancode, &scancode, sizeof(scancode));
+ ke->len = sizeof(scancode);
+ retval = dev->getkeycode(dev, scancode, &ke->keycode);
+ } else {
+ retval = dev->getkeycode_new(dev, ke);
+ }
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
return retval;
}
EXPORT_SYMBOL(input_get_keycode);
/**
- * input_get_keycode - assign new keycode to a given scancode
+ * input_set_keycode - attribute a keycode to a given scancode
* @dev: input device which keymap is being updated
- * @scancode: scancode (or its equivalent for device in question)
- * @keycode: new keycode to be assigned to the scancode
+ * @ke: new keymap entry
*
* This function should be called by anyone needing to update current
* keymap. Presently keyboard and evdev handlers use it.
*/
int input_set_keycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
+ const struct input_keymap_entry *ke)
{
unsigned long flags;
unsigned int old_keycode;
int retval;
- if (keycode > KEY_MAX)
+ if (ke->keycode > KEY_MAX)
return -EINVAL;
spin_lock_irqsave(&dev->event_lock, flags);
- retval = dev->getkeycode(dev, scancode, &old_keycode);
- if (retval)
- goto out;
+ if (dev->setkeycode) {
+ /*
+ * Support for legacy drivers, that don't implement the new
+ * ioctls
+ */
+ unsigned int scancode;
+
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ /*
+ * We need to know the old scancode, in order to generate a
+ * keyup effect, if the set operation happens successfully
+ */
+ if (!dev->getkeycode) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ retval = dev->getkeycode(dev, scancode, &old_keycode);
+ if (retval)
+ goto out;
+
+ retval = dev->setkeycode(dev, scancode, ke->keycode);
+ } else {
+ retval = dev->setkeycode_new(dev, ke, &old_keycode);
+ }
- retval = dev->setkeycode(dev, scancode, keycode);
if (retval)
goto out;
@@ -1601,7 +1697,7 @@ EXPORT_SYMBOL(input_free_device);
*
* This function allocates all necessary memory for MT slot handling in the
* input device, and adds ABS_MT_SLOT to the device capabilities. All slots
- * are initially marked as unused iby setting ABS_MT_TRACKING_ID to -1.
+ * are initially marked as unused by setting ABS_MT_TRACKING_ID to -1.
*/
int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
{
@@ -1759,11 +1855,11 @@ int input_register_device(struct input_dev *dev)
dev->rep[REP_PERIOD] = 33;
}
- if (!dev->getkeycode)
- dev->getkeycode = input_default_getkeycode;
+ if (!dev->getkeycode && !dev->getkeycode_new)
+ dev->getkeycode_new = input_default_getkeycode;
- if (!dev->setkeycode)
- dev->setkeycode = input_default_setkeycode;
+ if (!dev->setkeycode && !dev->setkeycode_new)
+ dev->setkeycode_new = input_default_setkeycode;
dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index aa037fec2f86..0426630f0e98 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -327,6 +327,16 @@ config KEYBOARD_NEWTON
To compile this driver as a module, choose M here: the
module will be called newtonkbd.
+config KEYBOARD_NOMADIK
+ tristate "ST-Ericsson Nomadik SKE keyboard"
+ depends on PLAT_NOMADIK
+ help
+ Say Y here if you want to use a keypad provided on the SKE controller
+ used on the Ux500 and Nomadik platforms
+
+ To compile this driver as a module, choose M here: the
+ module will be called nmk-ske-keypad.
+
config KEYBOARD_OPENCORES
tristate "OpenCores Keyboard Controller"
help
@@ -424,6 +434,15 @@ config KEYBOARD_OMAP
To compile this driver as a module, choose M here: the
module will be called omap-keypad.
+config KEYBOARD_OMAP4
+ tristate "TI OMAP4 keypad support"
+ depends on ARCH_OMAP4
+ help
+ Say Y here if you want to use the OMAP4 keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called omap4-keypad.
+
config KEYBOARD_TWL4030
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
depends on TWL4030_CORE
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 504b591be0cd..c13809c5c3a7 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -28,7 +28,9 @@ obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
+obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
+obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index d6918cb966c0..b92d1cd5cba1 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -660,7 +660,7 @@ static const struct dev_pm_ops adp5588_dev_pm_ops = {
#endif
static const struct i2c_device_id adp5588_id[] = {
- { KBUILD_MODNAME, 0 },
+ { "adp5588-keys", 0 },
{ "adp5587-keys", 0 },
{ }
};
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index 19fa94af207a..fed31e0947a1 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -570,6 +570,8 @@ static struct serio_device_id hil_dev_ids[] = {
{ 0 }
};
+MODULE_DEVICE_TABLE(serio, hil_dev_ids);
+
static struct serio_driver hil_serio_drv = {
.driver = {
.name = "hil_dev",
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
new file mode 100644
index 000000000000..6e0f23091360
--- /dev/null
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * License terms:GNU General Public License (GPL) version 2
+ *
+ * Keypad controller driver for the SKE (Scroll Key Encoder) module used in
+ * the Nomadik 8815 and Ux500 platforms.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include <plat/ske.h>
+
+/* SKE_CR bits */
+#define SKE_KPMLT (0x1 << 6)
+#define SKE_KPCN (0x7 << 3)
+#define SKE_KPASEN (0x1 << 2)
+#define SKE_KPASON (0x1 << 7)
+
+/* SKE_IMSC bits */
+#define SKE_KPIMA (0x1 << 2)
+
+/* SKE_ICR bits */
+#define SKE_KPICS (0x1 << 3)
+#define SKE_KPICA (0x1 << 2)
+
+/* SKE_RIS bits */
+#define SKE_KPRISA (0x1 << 2)
+
+#define SKE_KEYPAD_ROW_SHIFT 3
+#define SKE_KPD_KEYMAP_SIZE (8 * 8)
+
+/* keypad auto scan registers */
+#define SKE_ASR0 0x20
+#define SKE_ASR1 0x24
+#define SKE_ASR2 0x28
+#define SKE_ASR3 0x2C
+
+#define SKE_NUM_ASRX_REGISTERS (4)
+
+/**
+ * struct ske_keypad - data structure used by keypad driver
+ * @irq: irq no
+ * @reg_base: ske regsiters base address
+ * @input: pointer to input device object
+ * @board: keypad platform device
+ * @keymap: matrix scan code table for keycodes
+ * @clk: clock structure pointer
+ */
+struct ske_keypad {
+ int irq;
+ void __iomem *reg_base;
+ struct input_dev *input;
+ const struct ske_keypad_platform_data *board;
+ unsigned short keymap[SKE_KPD_KEYMAP_SIZE];
+ struct clk *clk;
+ spinlock_t ske_keypad_lock;
+};
+
+static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr,
+ u8 mask, u8 data)
+{
+ u32 ret;
+
+ spin_lock(&keypad->ske_keypad_lock);
+
+ ret = readl(keypad->reg_base + addr);
+ ret &= ~mask;
+ ret |= data;
+ writel(ret, keypad->reg_base + addr);
+
+ spin_unlock(&keypad->ske_keypad_lock);
+}
+
+/*
+ * ske_keypad_chip_init: init keypad controller configuration
+ *
+ * Enable Multi key press detection, auto scan mode
+ */
+static int __devinit ske_keypad_chip_init(struct ske_keypad *keypad)
+{
+ u32 value;
+ int timeout = 50;
+
+ /* check SKE_RIS to be 0 */
+ while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--)
+ cpu_relax();
+
+ if (!timeout)
+ return -EINVAL;
+
+ /*
+ * set debounce value
+ * keypad dbounce is configured in DBCR[15:8]
+ * dbounce value in steps of 32/32.768 ms
+ */
+ spin_lock(&keypad->ske_keypad_lock);
+ value = readl(keypad->reg_base + SKE_DBCR);
+ value = value & 0xff;
+ value |= ((keypad->board->debounce_ms * 32000)/32768) << 8;
+ writel(value, keypad->reg_base + SKE_DBCR);
+ spin_unlock(&keypad->ske_keypad_lock);
+
+ /* enable multi key detection */
+ ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPMLT);
+
+ /*
+ * set up the number of columns
+ * KPCN[5:3] defines no. of keypad columns to be auto scanned
+ */
+ value = (keypad->board->kcol - 1) << 3;
+ ske_keypad_set_bits(keypad, SKE_CR, SKE_KPCN, value);
+
+ /* clear keypad interrupt for auto(and pending SW) scans */
+ ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA | SKE_KPICS);
+
+ /* un-mask keypad interrupts */
+ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+ /* enable automatic scan */
+ ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPASEN);
+
+ return 0;
+}
+
+static void ske_keypad_read_data(struct ske_keypad *keypad)
+{
+ struct input_dev *input = keypad->input;
+ u16 status;
+ int col = 0, row = 0, code;
+ int ske_asr, ske_ris, key_pressed, i;
+
+ /*
+ * Read the auto scan registers
+ *
+ * Each SKE_ASRx (x=0 to x=3) contains two row values.
+ * lower byte contains row value for column 2*x,
+ * upper byte contains row value for column 2*x + 1
+ */
+ for (i = 0; i < SKE_NUM_ASRX_REGISTERS; i++) {
+ ske_asr = readl(keypad->reg_base + SKE_ASR0 + (4 * i));
+ if (!ske_asr)
+ continue;
+
+ /* now that ASRx is zero, find out the column x and row y*/
+ if (ske_asr & 0xff) {
+ col = i * 2;
+ status = ske_asr & 0xff;
+ } else {
+ col = (i * 2) + 1;
+ status = (ske_asr & 0xff00) >> 8;
+ }
+
+ /* find out the row */
+ row = __ffs(status);
+
+ code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT);
+ ske_ris = readl(keypad->reg_base + SKE_RIS);
+ key_pressed = ske_ris & SKE_KPRISA;
+
+ input_event(input, EV_MSC, MSC_SCAN, code);
+ input_report_key(input, keypad->keymap[code], key_pressed);
+ input_sync(input);
+ }
+}
+
+static irqreturn_t ske_keypad_irq(int irq, void *dev_id)
+{
+ struct ske_keypad *keypad = dev_id;
+ int retries = 20;
+
+ /* disable auto scan interrupt; mask the interrupt generated */
+ ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
+ ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA);
+
+ while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --retries)
+ msleep(5);
+
+ if (retries) {
+ /* SKEx registers are stable and can be read */
+ ske_keypad_read_data(keypad);
+ }
+
+ /* enable auto scan interrupts */
+ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit ske_keypad_probe(struct platform_device *pdev)
+{
+ const struct ske_keypad_platform_data *plat = pdev->dev.platform_data;
+ struct ske_keypad *keypad;
+ struct input_dev *input;
+ struct resource *res;
+ int irq;
+ int error;
+
+ if (!plat) {
+ dev_err(&pdev->dev, "invalid keypad platform data\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get keypad irq\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing platform resources\n");
+ return -EINVAL;
+ }
+
+ keypad = kzalloc(sizeof(struct ske_keypad), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!keypad || !input) {
+ dev_err(&pdev->dev, "failed to allocate keypad memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ keypad->irq = irq;
+ keypad->board = plat;
+ keypad->input = input;
+ spin_lock_init(&keypad->ske_keypad_lock);
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ error = -EBUSY;
+ goto err_free_mem;
+ }
+
+ keypad->reg_base = ioremap(res->start, resource_size(res));
+ if (!keypad->reg_base) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ error = -ENXIO;
+ goto err_free_mem_region;
+ }
+
+ keypad->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(keypad->clk)) {
+ dev_err(&pdev->dev, "failed to get clk\n");
+ error = PTR_ERR(keypad->clk);
+ goto err_iounmap;
+ }
+
+ input->id.bustype = BUS_HOST;
+ input->name = "ux500-ske-keypad";
+ input->dev.parent = &pdev->dev;
+
+ input->keycode = keypad->keymap;
+ input->keycodesize = sizeof(keypad->keymap[0]);
+ input->keycodemax = ARRAY_SIZE(keypad->keymap);
+
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+
+ __set_bit(EV_KEY, input->evbit);
+ if (!plat->no_autorepeat)
+ __set_bit(EV_REP, input->evbit);
+
+ matrix_keypad_build_keymap(plat->keymap_data, SKE_KEYPAD_ROW_SHIFT,
+ input->keycode, input->keybit);
+
+ clk_enable(keypad->clk);
+
+ /* go through board initialization helpers */
+ if (keypad->board->init)
+ keypad->board->init();
+
+ error = ske_keypad_chip_init(keypad);
+ if (error) {
+ dev_err(&pdev->dev, "unable to init keypad hardware\n");
+ goto err_clk_disable;
+ }
+
+ error = request_threaded_irq(keypad->irq, NULL, ske_keypad_irq,
+ IRQF_ONESHOT, "ske-keypad", keypad);
+ if (error) {
+ dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq);
+ goto err_clk_disable;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev,
+ "unable to register input device: %d\n", error);
+ goto err_free_irq;
+ }
+
+ if (plat->wakeup_enable)
+ device_init_wakeup(&pdev->dev, true);
+
+ platform_set_drvdata(pdev, keypad);
+
+ return 0;
+
+err_free_irq:
+ free_irq(keypad->irq, keypad);
+err_clk_disable:
+ clk_disable(keypad->clk);
+ clk_put(keypad->clk);
+err_iounmap:
+ iounmap(keypad->reg_base);
+err_free_mem_region:
+ release_mem_region(res->start, resource_size(res));
+err_free_mem:
+ input_free_device(input);
+ kfree(keypad);
+ return error;
+}
+
+static int __devexit ske_keypad_remove(struct platform_device *pdev)
+{
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ free_irq(keypad->irq, keypad);
+
+ input_unregister_device(keypad->input);
+
+ clk_disable(keypad->clk);
+ clk_put(keypad->clk);
+
+ if (keypad->board->exit)
+ keypad->board->exit();
+
+ iounmap(keypad->reg_base);
+ release_mem_region(res->start, resource_size(res));
+ kfree(keypad);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ske_keypad_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(irq);
+ else
+ ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
+
+ return 0;
+}
+
+static int ske_keypad_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(irq);
+ else
+ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ske_keypad_dev_pm_ops = {
+ .suspend = ske_keypad_suspend,
+ .resume = ske_keypad_resume,
+};
+#endif
+
+struct platform_driver ske_keypad_driver = {
+ .driver = {
+ .name = "nmk-ske-keypad",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &ske_keypad_dev_pm_ops,
+#endif
+ },
+ .probe = ske_keypad_probe,
+ .remove = __devexit_p(ske_keypad_remove),
+};
+
+static int __init ske_keypad_init(void)
+{
+ return platform_driver_probe(&ske_keypad_driver, ske_keypad_probe);
+}
+module_init(ske_keypad_init);
+
+static void __exit ske_keypad_exit(void)
+{
+ platform_driver_unregister(&ske_keypad_driver);
+}
+module_exit(ske_keypad_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("Nomadik Scroll-Key-Encoder Keypad Driver");
+MODULE_ALIAS("platform:nomadik-ske-keypad");
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
new file mode 100644
index 000000000000..45bd0977d006
--- /dev/null
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -0,0 +1,318 @@
+/*
+ * OMAP4 Keypad Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * Author: Abraham Arce <x0066660@ti.com>
+ * Initial Code: Syed Rafiuddin <rafiuddin.syed@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include <plat/omap4-keypad.h>
+
+/* OMAP4 registers */
+#define OMAP4_KBD_REVISION 0x00
+#define OMAP4_KBD_SYSCONFIG 0x10
+#define OMAP4_KBD_SYSSTATUS 0x14
+#define OMAP4_KBD_IRQSTATUS 0x18
+#define OMAP4_KBD_IRQENABLE 0x1C
+#define OMAP4_KBD_WAKEUPENABLE 0x20
+#define OMAP4_KBD_PENDING 0x24
+#define OMAP4_KBD_CTRL 0x28
+#define OMAP4_KBD_DEBOUNCINGTIME 0x2C
+#define OMAP4_KBD_LONGKEYTIME 0x30
+#define OMAP4_KBD_TIMEOUT 0x34
+#define OMAP4_KBD_STATEMACHINE 0x38
+#define OMAP4_KBD_ROWINPUTS 0x3C
+#define OMAP4_KBD_COLUMNOUTPUTS 0x40
+#define OMAP4_KBD_FULLCODE31_0 0x44
+#define OMAP4_KBD_FULLCODE63_32 0x48
+
+/* OMAP4 bit definitions */
+#define OMAP4_DEF_IRQENABLE_EVENTEN (1 << 0)
+#define OMAP4_DEF_IRQENABLE_LONGKEY (1 << 1)
+#define OMAP4_DEF_IRQENABLE_TIMEOUTEN (1 << 2)
+#define OMAP4_DEF_WUP_EVENT_ENA (1 << 0)
+#define OMAP4_DEF_WUP_LONG_KEY_ENA (1 << 1)
+#define OMAP4_DEF_CTRL_NOSOFTMODE (1 << 1)
+#define OMAP4_DEF_CTRLPTVVALUE (1 << 2)
+#define OMAP4_DEF_CTRLPTV (1 << 1)
+
+/* OMAP4 values */
+#define OMAP4_VAL_IRQDISABLE 0x00
+#define OMAP4_VAL_DEBOUNCINGTIME 0x07
+#define OMAP4_VAL_FUNCTIONALCFG 0x1E
+
+#define OMAP4_MASK_IRQSTATUSDISABLE 0xFFFF
+
+struct omap4_keypad {
+ struct input_dev *input;
+
+ void __iomem *base;
+ int irq;
+
+ unsigned int rows;
+ unsigned int cols;
+ unsigned int row_shift;
+ unsigned char key_state[8];
+ unsigned short keymap[];
+};
+
+static void __devinit omap4_keypad_config(struct omap4_keypad *keypad_data)
+{
+ __raw_writel(OMAP4_VAL_FUNCTIONALCFG,
+ keypad_data->base + OMAP4_KBD_CTRL);
+ __raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
+ keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
+ __raw_writel(OMAP4_VAL_IRQDISABLE,
+ keypad_data->base + OMAP4_KBD_IRQSTATUS);
+ __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
+ keypad_data->base + OMAP4_KBD_IRQENABLE);
+ __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
+ keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
+}
+
+/* Interrupt handler */
+static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
+{
+ struct omap4_keypad *keypad_data = dev_id;
+ struct input_dev *input_dev = keypad_data->input;
+ unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)];
+ unsigned int col, row, code, changed;
+ u32 *new_state = (u32 *) key_state;
+
+ /* Disable interrupts */
+ __raw_writel(OMAP4_VAL_IRQDISABLE,
+ keypad_data->base + OMAP4_KBD_IRQENABLE);
+
+ *new_state = __raw_readl(keypad_data->base + OMAP4_KBD_FULLCODE31_0);
+ *(new_state + 1) = __raw_readl(keypad_data->base
+ + OMAP4_KBD_FULLCODE63_32);
+
+ for (row = 0; row < keypad_data->rows; row++) {
+ changed = key_state[row] ^ keypad_data->key_state[row];
+ if (!changed)
+ continue;
+
+ for (col = 0; col < keypad_data->cols; col++) {
+ if (changed & (1 << col)) {
+ code = MATRIX_SCAN_CODE(row, col,
+ keypad_data->row_shift);
+ input_event(input_dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(input_dev,
+ keypad_data->keymap[code],
+ key_state[row] & (1 << col));
+ }
+ }
+ }
+
+ input_sync(input_dev);
+
+ memcpy(keypad_data->key_state, key_state,
+ sizeof(keypad_data->key_state));
+
+ /* clear pending interrupts */
+ __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
+ keypad_data->base + OMAP4_KBD_IRQSTATUS);
+
+ /* enable interrupts */
+ __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
+ keypad_data->base + OMAP4_KBD_IRQENABLE);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit omap4_keypad_probe(struct platform_device *pdev)
+{
+ const struct omap4_keypad_platform_data *pdata;
+ struct omap4_keypad *keypad_data;
+ struct input_dev *input_dev;
+ struct resource *res;
+ resource_size_t size;
+ unsigned int row_shift, max_keys;
+ int irq;
+ int error;
+
+ /* platform data */
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data defined\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no base address specified\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no keyboard irq assigned\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->keymap_data) {
+ dev_err(&pdev->dev, "no keymap data defined\n");
+ return -EINVAL;
+ }
+
+ row_shift = get_count_order(pdata->cols);
+ max_keys = pdata->rows << row_shift;
+
+ keypad_data = kzalloc(sizeof(struct omap4_keypad) +
+ max_keys * sizeof(keypad_data->keymap[0]),
+ GFP_KERNEL);
+ if (!keypad_data) {
+ dev_err(&pdev->dev, "keypad_data memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ size = resource_size(res);
+
+ res = request_mem_region(res->start, size, pdev->name);
+ if (!res) {
+ dev_err(&pdev->dev, "can't request mem region\n");
+ error = -EBUSY;
+ goto err_free_keypad;
+ }
+
+ keypad_data->base = ioremap(res->start, resource_size(res));
+ if (!keypad_data->base) {
+ dev_err(&pdev->dev, "can't ioremap mem resource\n");
+ error = -ENOMEM;
+ goto err_release_mem;
+ }
+
+ keypad_data->irq = irq;
+ keypad_data->row_shift = row_shift;
+ keypad_data->rows = pdata->rows;
+ keypad_data->cols = pdata->cols;
+
+ /* input device allocation */
+ keypad_data->input = input_dev = input_allocate_device();
+ if (!input_dev) {
+ error = -ENOMEM;
+ goto err_unmap;
+ }
+
+ input_dev->name = pdev->name;
+ input_dev->dev.parent = &pdev->dev;
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0001;
+
+ input_dev->keycode = keypad_data->keymap;
+ input_dev->keycodesize = sizeof(keypad_data->keymap[0]);
+ input_dev->keycodemax = max_keys;
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_REP, input_dev->evbit);
+
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+ input_set_drvdata(input_dev, keypad_data);
+
+ matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
+ input_dev->keycode, input_dev->keybit);
+
+ omap4_keypad_config(keypad_data);
+
+ error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
+ IRQF_TRIGGER_RISING,
+ "omap4-keypad", keypad_data);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register interrupt\n");
+ goto err_free_input;
+ }
+
+ error = input_register_device(keypad_data->input);
+ if (error < 0) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ goto err_free_irq;
+ }
+
+
+ platform_set_drvdata(pdev, keypad_data);
+ return 0;
+
+err_free_irq:
+ free_irq(keypad_data->irq, keypad_data);
+err_free_input:
+ input_free_device(input_dev);
+err_unmap:
+ iounmap(keypad_data->base);
+err_release_mem:
+ release_mem_region(res->start, size);
+err_free_keypad:
+ kfree(keypad_data);
+ return error;
+}
+
+static int __devexit omap4_keypad_remove(struct platform_device *pdev)
+{
+ struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ free_irq(keypad_data->irq, keypad_data);
+ input_unregister_device(keypad_data->input);
+
+ iounmap(keypad_data->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(keypad_data);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver omap4_keypad_driver = {
+ .probe = omap4_keypad_probe,
+ .remove = __devexit_p(omap4_keypad_remove),
+ .driver = {
+ .name = "omap4-keypad",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap4_keypad_init(void)
+{
+ return platform_driver_register(&omap4_keypad_driver);
+}
+module_init(omap4_keypad_init);
+
+static void __exit omap4_keypad_exit(void)
+{
+ platform_driver_unregister(&omap4_keypad_driver);
+}
+module_exit(omap4_keypad_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("OMAP4 Keypad Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap4-keypad");
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index fb16b5e5ea13..09bef79d9da1 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -406,23 +406,22 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev)
if (error) {
dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n",
kp->irq);
- goto err3;
+ goto err2;
}
/* Enable KP and TO interrupts now. */
reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO);
if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) {
error = -EIO;
- goto err4;
+ goto err3;
}
platform_set_drvdata(pdev, kp);
return 0;
-err4:
+err3:
/* mask all events - we don't care about the result */
(void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1);
-err3:
free_irq(kp->irq, NULL);
err2:
input_unregister_device(input);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index b49e23379723..b99b8cbde02f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -22,6 +22,16 @@ config INPUT_88PM860X_ONKEY
To compile this driver as a module, choose M here: the module
will be called 88pm860x_onkey.
+config INPUT_AB8500_PONKEY
+ tristate "AB8500 Pon (PowerOn) Key"
+ depends on AB8500_CORE
+ help
+ Say Y here to use the PowerOn Key for ST-Ericsson's AB8500
+ Mix-Sig PMIC.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ab8500-ponkey.
+
config INPUT_AD714X
tristate "Analog Devices AD714x Capacitance Touch Sensor"
help
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 19ccca78fa76..1fe1f6c8b737 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -5,6 +5,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
+obj-$(CONFIG_INPUT_AB8500_PONKEY) += ab8500-ponkey.o
obj-$(CONFIG_INPUT_AD714X) += ad714x.o
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c
new file mode 100644
index 000000000000..3d3288a78fdc
--- /dev/null
+++ b/drivers/input/misc/ab8500-ponkey.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * AB8500 Power-On Key handler
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/slab.h>
+
+/**
+ * struct ab8500_ponkey - ab8500 ponkey information
+ * @input_dev: pointer to input device
+ * @ab8500: ab8500 parent
+ * @irq_dbf: irq number for falling transition
+ * @irq_dbr: irq number for rising transition
+ */
+struct ab8500_ponkey {
+ struct input_dev *idev;
+ struct ab8500 *ab8500;
+ int irq_dbf;
+ int irq_dbr;
+};
+
+/* AB8500 gives us an interrupt when ONKEY is held */
+static irqreturn_t ab8500_ponkey_handler(int irq, void *data)
+{
+ struct ab8500_ponkey *ponkey = data;
+
+ if (irq == ponkey->irq_dbf)
+ input_report_key(ponkey->idev, KEY_POWER, true);
+ else if (irq == ponkey->irq_dbr)
+ input_report_key(ponkey->idev, KEY_POWER, false);
+
+ input_sync(ponkey->idev);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit ab8500_ponkey_probe(struct platform_device *pdev)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+ struct ab8500_ponkey *ponkey;
+ struct input_dev *input;
+ int irq_dbf, irq_dbr;
+ int error;
+
+ irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF");
+ if (irq_dbf < 0) {
+ dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf);
+ return irq_dbf;
+ }
+
+ irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR");
+ if (irq_dbr < 0) {
+ dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr);
+ return irq_dbr;
+ }
+
+ ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!ponkey || !input) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ ponkey->idev = input;
+ ponkey->ab8500 = ab8500;
+ ponkey->irq_dbf = irq_dbf;
+ ponkey->irq_dbr = irq_dbr;
+
+ input->name = "AB8500 POn(PowerOn) Key";
+ input->dev.parent = &pdev->dev;
+
+ input_set_capability(input, EV_KEY, KEY_POWER);
+
+ error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler,
+ 0, "ab8500-ponkey-dbf", ponkey);
+ if (error < 0) {
+ dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
+ ponkey->irq_dbf, error);
+ goto err_free_mem;
+ }
+
+ error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler,
+ 0, "ab8500-ponkey-dbr", ponkey);
+ if (error < 0) {
+ dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
+ ponkey->irq_dbr, error);
+ goto err_free_dbf_irq;
+ }
+
+ error = input_register_device(ponkey->idev);
+ if (error) {
+ dev_err(ab8500->dev, "Can't register input device: %d\n", error);
+ goto err_free_dbr_irq;
+ }
+
+ platform_set_drvdata(pdev, ponkey);
+ return 0;
+
+err_free_dbr_irq:
+ free_irq(ponkey->irq_dbr, ponkey);
+err_free_dbf_irq:
+ free_irq(ponkey->irq_dbf, ponkey);
+err_free_mem:
+ input_free_device(input);
+ kfree(ponkey);
+
+ return error;
+}
+
+static int __devexit ab8500_ponkey_remove(struct platform_device *pdev)
+{
+ struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev);
+
+ free_irq(ponkey->irq_dbf, ponkey);
+ free_irq(ponkey->irq_dbr, ponkey);
+ input_unregister_device(ponkey->idev);
+ kfree(ponkey);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ab8500_ponkey_driver = {
+ .driver = {
+ .name = "ab8500-poweron-key",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_ponkey_probe,
+ .remove = __devexit_p(ab8500_ponkey_remove),
+};
+
+static int __init ab8500_ponkey_init(void)
+{
+ return platform_driver_register(&ab8500_ponkey_driver);
+}
+module_init(ab8500_ponkey_init);
+
+static void __exit ab8500_ponkey_exit(void)
+{
+ platform_driver_unregister(&ab8500_ponkey_driver);
+}
+module_exit(ab8500_ponkey_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver");
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 23257652b8e8..0b0e9be63542 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -483,51 +483,88 @@ static void ati_remote2_complete_key(struct urb *urb)
}
static int ati_remote2_getkeycode(struct input_dev *idev,
- unsigned int scancode, unsigned int *keycode)
+ struct input_keymap_entry *ke)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
unsigned int mode;
- int index;
+ int offset;
+ unsigned int index;
+ unsigned int scancode;
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ if (index >= ATI_REMOTE2_MODES *
+ ARRAY_SIZE(ati_remote2_key_table))
+ return -EINVAL;
+
+ mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
+ offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
+ scancode = (mode << 8) + ati_remote2_key_table[offset].hw_code;
+ } else {
+ if (input_scancode_to_scalar(ke, &scancode))
+ return -EINVAL;
+
+ mode = scancode >> 8;
+ if (mode > ATI_REMOTE2_PC)
+ return -EINVAL;
+
+ offset = ati_remote2_lookup(scancode & 0xff);
+ if (offset < 0)
+ return -EINVAL;
+
+ index = mode * ARRAY_SIZE(ati_remote2_key_table) + offset;
+ }
- mode = scancode >> 8;
- if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask))
- return -EINVAL;
+ ke->keycode = ar2->keycode[mode][offset];
+ ke->len = sizeof(scancode);
+ memcpy(&ke->scancode, &scancode, sizeof(scancode));
+ ke->index = index;
- index = ati_remote2_lookup(scancode & 0xFF);
- if (index < 0)
- return -EINVAL;
-
- *keycode = ar2->keycode[mode][index];
return 0;
}
static int ati_remote2_setkeycode(struct input_dev *idev,
- unsigned int scancode, unsigned int keycode)
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
- unsigned int mode, old_keycode;
- int index;
-
- mode = scancode >> 8;
- if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask))
- return -EINVAL;
-
- index = ati_remote2_lookup(scancode & 0xFF);
- if (index < 0)
- return -EINVAL;
+ unsigned int mode;
+ int offset;
+ unsigned int index;
+ unsigned int scancode;
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ if (ke->index >= ATI_REMOTE2_MODES *
+ ARRAY_SIZE(ati_remote2_key_table))
+ return -EINVAL;
+
+ mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
+ offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
+ } else {
+ if (input_scancode_to_scalar(ke, &scancode))
+ return -EINVAL;
+
+ mode = scancode >> 8;
+ if (mode > ATI_REMOTE2_PC)
+ return -EINVAL;
+
+ offset = ati_remote2_lookup(scancode & 0xff);
+ if (offset < 0)
+ return -EINVAL;
+ }
- old_keycode = ar2->keycode[mode][index];
- ar2->keycode[mode][index] = keycode;
- __set_bit(keycode, idev->keybit);
+ *old_keycode = ar2->keycode[mode][offset];
+ ar2->keycode[mode][offset] = ke->keycode;
+ __set_bit(ke->keycode, idev->keybit);
for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
- if (ar2->keycode[mode][index] == old_keycode)
+ if (ar2->keycode[mode][index] == *old_keycode)
return 0;
}
}
- __clear_bit(old_keycode, idev->keybit);
+ __clear_bit(*old_keycode, idev->keybit);
return 0;
}
@@ -575,8 +612,8 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
idev->open = ati_remote2_open;
idev->close = ati_remote2_close;
- idev->getkeycode = ati_remote2_getkeycode;
- idev->setkeycode = ati_remote2_setkeycode;
+ idev->getkeycode_new = ati_remote2_getkeycode;
+ idev->setkeycode_new = ati_remote2_setkeycode;
idev->name = ar2->name;
idev->phys = ar2->phys;
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
index bf170f6b4422..f45947190e4f 100644
--- a/drivers/input/misc/powermate.c
+++ b/drivers/input/misc/powermate.c
@@ -280,7 +280,7 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev
pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL);
if (!pm->configcr)
- return -1;
+ return -ENOMEM;
return 0;
}
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 48311204ba51..04d9bf320a4f 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -699,7 +699,7 @@ int elantech_init(struct psmouse *psmouse)
psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
if (!etd)
- return -1;
+ return -ENOMEM;
etd->parity[0] = 1;
for (i = 1; i < 256; i++)
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 73a7af2542a8..cd9d0c97e429 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1584,10 +1584,10 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
if (!new_dev)
return -ENOMEM;
- while (serio->child) {
+ while (!list_empty(&serio->children)) {
if (++retry > 3) {
printk(KERN_WARNING
- "psmouse: failed to destroy child port, "
+ "psmouse: failed to destroy children ports, "
"protocol change aborted.\n");
input_free_device(new_dev);
return -EIO;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 96b70a43515f..2e300a460556 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -294,7 +294,29 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c)
return 0;
}
-static inline int synaptics_is_pt_packet(unsigned char *buf)
+static int synaptics_pt_start(struct serio *serio)
+{
+ struct psmouse *parent = serio_get_drvdata(serio->parent);
+ struct synaptics_data *priv = parent->private;
+
+ serio_pause_rx(parent->ps2dev.serio);
+ priv->pt_port = serio;
+ serio_continue_rx(parent->ps2dev.serio);
+
+ return 0;
+}
+
+static void synaptics_pt_stop(struct serio *serio)
+{
+ struct psmouse *parent = serio_get_drvdata(serio->parent);
+ struct synaptics_data *priv = parent->private;
+
+ serio_pause_rx(parent->ps2dev.serio);
+ priv->pt_port = NULL;
+ serio_continue_rx(parent->ps2dev.serio);
+}
+
+static int synaptics_is_pt_packet(unsigned char *buf)
{
return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
}
@@ -315,9 +337,8 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
static void synaptics_pt_activate(struct psmouse *psmouse)
{
- struct serio *ptport = psmouse->ps2dev.serio->child;
- struct psmouse *child = serio_get_drvdata(ptport);
struct synaptics_data *priv = psmouse->private;
+ struct psmouse *child = serio_get_drvdata(priv->pt_port);
/* adjust the touchpad to child's choice of protocol */
if (child) {
@@ -345,6 +366,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
serio->write = synaptics_pt_write;
+ serio->start = synaptics_pt_start;
+ serio->stop = synaptics_pt_stop;
serio->parent = psmouse->ps2dev.serio;
psmouse->pt_activate = synaptics_pt_activate;
@@ -578,9 +601,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
if (unlikely(priv->pkt_type == SYN_NEWABS))
priv->pkt_type = synaptics_detect_pkt_type(psmouse);
- if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) {
- if (psmouse->ps2dev.serio->child)
- synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet);
+ if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
+ synaptics_is_pt_packet(psmouse->packet)) {
+ if (priv->pt_port)
+ synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
} else
synaptics_process_packet(psmouse);
@@ -731,7 +755,7 @@ int synaptics_init(struct psmouse *psmouse)
psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
- return -1;
+ return -ENOMEM;
psmouse_reset(psmouse);
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index b6aa7d20d8a3..613a3652f98f 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -110,6 +110,8 @@ struct synaptics_data {
unsigned char pkt_type; /* packet type - old, new, etc */
unsigned char mode; /* current mode byte */
int scroll;
+
+ struct serio *pt_port; /* Pass-through serio port */
};
void synaptics_module_init(void);
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 0643e49ca603..54b2fa892e19 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -303,7 +303,7 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
if (!psmouse->private)
- return -1;
+ return -ENOMEM;
psmouse->vendor = "IBM";
psmouse->name = "TrackPoint";
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 31ec7265aac6..2a00ddf4f23a 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -867,7 +867,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
spin_lock_init(&mousedev->client_lock);
mutex_init(&mousedev->mutex);
lockdep_set_subclass(&mousedev->mutex,
- minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
+ minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0);
init_waitqueue_head(&mousedev->wait);
if (minor == MOUSEDEV_MIX)
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 3bfe8fafc6ad..6256233d2bfb 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -226,4 +226,13 @@ config SERIO_AMS_DELTA
To compile this driver as a module, choose M here;
the module will be called ams_delta_serio.
+config SERIO_PS2MULT
+ tristate "TQC PS/2 multiplexer"
+ help
+ Say Y here if you have the PS/2 line multiplexer like the one
+ present on TQC boads.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ps2mult.
+
endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 84c80bf7185e..dbbe37616c92 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_HP_SDC) += hp_sdc.o
obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
+obj-$(CONFIG_SERIO_PS2MULT) += ps2mult.o
obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
obj-$(CONFIG_SERIO_RAW) += serio_raw.o
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index f58513160480..18db5a8c7478 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -1063,7 +1063,7 @@ static long i8042_panic_blink(int state)
#ifdef CONFIG_X86
static void i8042_dritek_enable(void)
{
- char param = 0x90;
+ unsigned char param = 0x90;
int error;
error = i8042_command(&param, 0x1059);
diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c
new file mode 100644
index 000000000000..6bce22e4e495
--- /dev/null
+++ b/drivers/input/serio/ps2mult.c
@@ -0,0 +1,318 @@
+/*
+ * TQC PS/2 Multiplexer driver
+ *
+ * Copyright (C) 2010 Dmitry Eremin-Solenikov
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>");
+MODULE_DESCRIPTION("TQC PS/2 Multiplexer driver");
+MODULE_LICENSE("GPL");
+
+#define PS2MULT_KB_SELECTOR 0xA0
+#define PS2MULT_MS_SELECTOR 0xA1
+#define PS2MULT_ESCAPE 0x7D
+#define PS2MULT_BSYNC 0x7E
+#define PS2MULT_SESSION_START 0x55
+#define PS2MULT_SESSION_END 0x56
+
+struct ps2mult_port {
+ struct serio *serio;
+ unsigned char sel;
+ bool registered;
+};
+
+#define PS2MULT_NUM_PORTS 2
+#define PS2MULT_KBD_PORT 0
+#define PS2MULT_MOUSE_PORT 1
+
+struct ps2mult {
+ struct serio *mx_serio;
+ struct ps2mult_port ports[PS2MULT_NUM_PORTS];
+
+ spinlock_t lock;
+ struct ps2mult_port *in_port;
+ struct ps2mult_port *out_port;
+ bool escape;
+};
+
+/* First MUST come PS2MULT_NUM_PORTS selectors */
+static const unsigned char ps2mult_controls[] = {
+ PS2MULT_KB_SELECTOR, PS2MULT_MS_SELECTOR,
+ PS2MULT_ESCAPE, PS2MULT_BSYNC,
+ PS2MULT_SESSION_START, PS2MULT_SESSION_END,
+};
+
+static const struct serio_device_id ps2mult_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_PS2MULT,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, ps2mult_serio_ids);
+
+static void ps2mult_select_port(struct ps2mult *psm, struct ps2mult_port *port)
+{
+ struct serio *mx_serio = psm->mx_serio;
+
+ serio_write(mx_serio, port->sel);
+ psm->out_port = port;
+ dev_dbg(&mx_serio->dev, "switched to sel %02x\n", port->sel);
+}
+
+static int ps2mult_serio_write(struct serio *serio, unsigned char data)
+{
+ struct serio *mx_port = serio->parent;
+ struct ps2mult *psm = serio_get_drvdata(mx_port);
+ struct ps2mult_port *port = serio->port_data;
+ bool need_escape;
+ unsigned long flags;
+
+ spin_lock_irqsave(&psm->lock, flags);
+
+ if (psm->out_port != port)
+ ps2mult_select_port(psm, port);
+
+ need_escape = memchr(ps2mult_controls, data, sizeof(ps2mult_controls));
+
+ dev_dbg(&serio->dev,
+ "write: %s%02x\n", need_escape ? "ESC " : "", data);
+
+ if (need_escape)
+ serio_write(mx_port, PS2MULT_ESCAPE);
+
+ serio_write(mx_port, data);
+
+ spin_unlock_irqrestore(&psm->lock, flags);
+
+ return 0;
+}
+
+static int ps2mult_serio_start(struct serio *serio)
+{
+ struct ps2mult *psm = serio_get_drvdata(serio->parent);
+ struct ps2mult_port *port = serio->port_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&psm->lock, flags);
+ port->registered = true;
+ spin_unlock_irqrestore(&psm->lock, flags);
+
+ return 0;
+}
+
+static void ps2mult_serio_stop(struct serio *serio)
+{
+ struct ps2mult *psm = serio_get_drvdata(serio->parent);
+ struct ps2mult_port *port = serio->port_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&psm->lock, flags);
+ port->registered = false;
+ spin_unlock_irqrestore(&psm->lock, flags);
+}
+
+static int ps2mult_create_port(struct ps2mult *psm, int i)
+{
+ struct serio *mx_serio = psm->mx_serio;
+ struct serio *serio;
+
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!serio)
+ return -ENOMEM;
+
+ strlcpy(serio->name, "TQC PS/2 Multiplexer", sizeof(serio->name));
+ snprintf(serio->phys, sizeof(serio->phys),
+ "%s/port%d", mx_serio->phys, i);
+ serio->id.type = SERIO_8042;
+ serio->write = ps2mult_serio_write;
+ serio->start = ps2mult_serio_start;
+ serio->stop = ps2mult_serio_stop;
+ serio->parent = psm->mx_serio;
+ serio->port_data = &psm->ports[i];
+
+ psm->ports[i].serio = serio;
+
+ return 0;
+}
+
+static void ps2mult_reset(struct ps2mult *psm)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&psm->lock, flags);
+
+ serio_write(psm->mx_serio, PS2MULT_SESSION_END);
+ serio_write(psm->mx_serio, PS2MULT_SESSION_START);
+
+ ps2mult_select_port(psm, &psm->ports[PS2MULT_KBD_PORT]);
+
+ spin_unlock_irqrestore(&psm->lock, flags);
+}
+
+static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct ps2mult *psm;
+ int i;
+ int error;
+
+ if (!serio->write)
+ return -EINVAL;
+
+ psm = kzalloc(sizeof(*psm), GFP_KERNEL);
+ if (!psm)
+ return -ENOMEM;
+
+ spin_lock_init(&psm->lock);
+ psm->mx_serio = serio;
+
+ for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
+ psm->ports[i].sel = ps2mult_controls[i];
+ error = ps2mult_create_port(psm, i);
+ if (error)
+ goto err_out;
+ }
+
+ psm->in_port = psm->out_port = &psm->ports[PS2MULT_KBD_PORT];
+
+ serio_set_drvdata(serio, psm);
+ error = serio_open(serio, drv);
+ if (error)
+ goto err_out;
+
+ ps2mult_reset(psm);
+
+ for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
+ struct serio *s = psm->ports[i].serio;
+
+ dev_info(&serio->dev, "%s port at %s\n", s->name, serio->phys);
+ serio_register_port(s);
+ }
+
+ return 0;
+
+err_out:
+ while (--i >= 0)
+ kfree(psm->ports[i].serio);
+ kfree(serio);
+ return error;
+}
+
+static void ps2mult_disconnect(struct serio *serio)
+{
+ struct ps2mult *psm = serio_get_drvdata(serio);
+
+ /* Note that serio core already take care of children ports */
+ serio_write(serio, PS2MULT_SESSION_END);
+ serio_close(serio);
+ kfree(psm);
+
+ serio_set_drvdata(serio, NULL);
+}
+
+static int ps2mult_reconnect(struct serio *serio)
+{
+ struct ps2mult *psm = serio_get_drvdata(serio);
+
+ ps2mult_reset(psm);
+
+ return 0;
+}
+
+static irqreturn_t ps2mult_interrupt(struct serio *serio,
+ unsigned char data, unsigned int dfl)
+{
+ struct ps2mult *psm = serio_get_drvdata(serio);
+ struct ps2mult_port *in_port;
+ unsigned long flags;
+
+ dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, dfl);
+
+ spin_lock_irqsave(&psm->lock, flags);
+
+ if (psm->escape) {
+ psm->escape = false;
+ in_port = psm->in_port;
+ if (in_port->registered)
+ serio_interrupt(in_port->serio, data, dfl);
+ goto out;
+ }
+
+ switch (data) {
+ case PS2MULT_ESCAPE:
+ dev_dbg(&serio->dev, "ESCAPE\n");
+ psm->escape = true;
+ break;
+
+ case PS2MULT_BSYNC:
+ dev_dbg(&serio->dev, "BSYNC\n");
+ psm->in_port = psm->out_port;
+ break;
+
+ case PS2MULT_SESSION_START:
+ dev_dbg(&serio->dev, "SS\n");
+ break;
+
+ case PS2MULT_SESSION_END:
+ dev_dbg(&serio->dev, "SE\n");
+ break;
+
+ case PS2MULT_KB_SELECTOR:
+ dev_dbg(&serio->dev, "KB\n");
+ psm->in_port = &psm->ports[PS2MULT_KBD_PORT];
+ break;
+
+ case PS2MULT_MS_SELECTOR:
+ dev_dbg(&serio->dev, "MS\n");
+ psm->in_port = &psm->ports[PS2MULT_MOUSE_PORT];
+ break;
+
+ default:
+ in_port = psm->in_port;
+ if (in_port->registered)
+ serio_interrupt(in_port->serio, data, dfl);
+ break;
+ }
+
+ out:
+ spin_unlock_irqrestore(&psm->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static struct serio_driver ps2mult_drv = {
+ .driver = {
+ .name = "ps2mult",
+ },
+ .description = "TQC PS/2 Multiplexer driver",
+ .id_table = ps2mult_serio_ids,
+ .interrupt = ps2mult_interrupt,
+ .connect = ps2mult_connect,
+ .disconnect = ps2mult_disconnect,
+ .reconnect = ps2mult_reconnect,
+};
+
+static int __init ps2mult_init(void)
+{
+ return serio_register_driver(&ps2mult_drv);
+}
+
+static void __exit ps2mult_exit(void)
+{
+ serio_unregister_driver(&ps2mult_drv);
+}
+
+module_init(ps2mult_init);
+module_exit(ps2mult_exit);
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index c3b626e9eae7..405bf214527c 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -37,7 +37,6 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
-#include <linux/freezer.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
@@ -56,7 +55,7 @@ static struct bus_type serio_bus;
static void serio_add_port(struct serio *serio);
static int serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio);
-static void serio_reconnect_chain(struct serio *serio);
+static void serio_reconnect_subtree(struct serio *serio);
static void serio_attach_driver(struct serio_driver *drv);
static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
@@ -152,7 +151,7 @@ static void serio_find_driver(struct serio *serio)
enum serio_event_type {
SERIO_RESCAN_PORT,
SERIO_RECONNECT_PORT,
- SERIO_RECONNECT_CHAIN,
+ SERIO_RECONNECT_SUBTREE,
SERIO_REGISTER_PORT,
SERIO_ATTACH_DRIVER,
};
@@ -292,8 +291,8 @@ static void serio_handle_event(void)
serio_find_driver(event->object);
break;
- case SERIO_RECONNECT_CHAIN:
- serio_reconnect_chain(event->object);
+ case SERIO_RECONNECT_SUBTREE:
+ serio_reconnect_subtree(event->object);
break;
case SERIO_ATTACH_DRIVER:
@@ -330,12 +329,10 @@ static void serio_remove_pending_events(void *object)
}
/*
- * Destroy child serio port (if any) that has not been fully registered yet.
+ * Locate child serio port (if any) that has not been fully registered yet.
*
- * Note that we rely on the fact that port can have only one child and therefore
- * only one child registration request can be pending. Additionally, children
- * are registered by driver's connect() handler so there can't be a grandchild
- * pending registration together with a child.
+ * Children are registered by driver's connect() handler so there can't be a
+ * grandchild pending registration together with a child.
*/
static struct serio *serio_get_pending_child(struct serio *parent)
{
@@ -449,7 +446,7 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
if (!strncmp(buf, "none", count)) {
serio_disconnect_port(serio);
} else if (!strncmp(buf, "reconnect", count)) {
- serio_reconnect_chain(serio);
+ serio_reconnect_subtree(serio);
} else if (!strncmp(buf, "rescan", count)) {
serio_disconnect_port(serio);
serio_find_driver(serio);
@@ -516,6 +513,8 @@ static void serio_init_port(struct serio *serio)
__module_get(THIS_MODULE);
INIT_LIST_HEAD(&serio->node);
+ INIT_LIST_HEAD(&serio->child_node);
+ INIT_LIST_HEAD(&serio->children);
spin_lock_init(&serio->lock);
mutex_init(&serio->drv_mutex);
device_initialize(&serio->dev);
@@ -538,12 +537,13 @@ static void serio_init_port(struct serio *serio)
*/
static void serio_add_port(struct serio *serio)
{
+ struct serio *parent = serio->parent;
int error;
- if (serio->parent) {
- serio_pause_rx(serio->parent);
- serio->parent->child = serio;
- serio_continue_rx(serio->parent);
+ if (parent) {
+ serio_pause_rx(parent);
+ list_add_tail(&serio->child_node, &parent->children);
+ serio_continue_rx(parent);
}
list_add_tail(&serio->node, &serio_list);
@@ -559,15 +559,14 @@ static void serio_add_port(struct serio *serio)
}
/*
- * serio_destroy_port() completes deregistration process and removes
+ * serio_destroy_port() completes unregistration process and removes
* port from the system
*/
static void serio_destroy_port(struct serio *serio)
{
struct serio *child;
- child = serio_get_pending_child(serio);
- if (child) {
+ while ((child = serio_get_pending_child(serio)) != NULL) {
serio_remove_pending_events(child);
put_device(&child->dev);
}
@@ -577,7 +576,7 @@ static void serio_destroy_port(struct serio *serio)
if (serio->parent) {
serio_pause_rx(serio->parent);
- serio->parent->child = NULL;
+ list_del_init(&serio->child_node);
serio_continue_rx(serio->parent);
serio->parent = NULL;
}
@@ -609,46 +608,82 @@ static int serio_reconnect_port(struct serio *serio)
}
/*
- * Reconnect serio port and all its children (re-initialize attached devices)
+ * Reconnect serio port and all its children (re-initialize attached
+ * devices).
*/
-static void serio_reconnect_chain(struct serio *serio)
+static void serio_reconnect_subtree(struct serio *root)
{
+ struct serio *s = root;
+ int error;
+
do {
- if (serio_reconnect_port(serio)) {
- /* Ok, old children are now gone, we are done */
- break;
+ error = serio_reconnect_port(s);
+ if (!error) {
+ /*
+ * Reconnect was successful, move on to do the
+ * first child.
+ */
+ if (!list_empty(&s->children)) {
+ s = list_first_entry(&s->children,
+ struct serio, child_node);
+ continue;
+ }
}
- serio = serio->child;
- } while (serio);
+
+ /*
+ * Either it was a leaf node or reconnect failed and it
+ * became a leaf node. Continue reconnecting starting with
+ * the next sibling of the parent node.
+ */
+ while (s != root) {
+ struct serio *parent = s->parent;
+
+ if (!list_is_last(&s->child_node, &parent->children)) {
+ s = list_entry(s->child_node.next,
+ struct serio, child_node);
+ break;
+ }
+
+ s = parent;
+ }
+ } while (s != root);
}
/*
* serio_disconnect_port() unbinds a port from its driver. As a side effect
- * all child ports are unbound and destroyed.
+ * all children ports are unbound and destroyed.
*/
static void serio_disconnect_port(struct serio *serio)
{
- struct serio *s, *parent;
+ struct serio *s = serio;
+
+ /*
+ * Children ports should be disconnected and destroyed
+ * first; we travel the tree in depth-first order.
+ */
+ while (!list_empty(&serio->children)) {
+
+ /* Locate a leaf */
+ while (!list_empty(&s->children))
+ s = list_first_entry(&s->children,
+ struct serio, child_node);
- if (serio->child) {
/*
- * Children ports should be disconnected and destroyed
- * first, staring with the leaf one, since we don't want
- * to do recursion
+ * Prune this leaf node unless it is the one we
+ * started with.
*/
- for (s = serio; s->child; s = s->child)
- /* empty */;
-
- do {
- parent = s->parent;
+ if (s != serio) {
+ struct serio *parent = s->parent;
device_release_driver(&s->dev);
serio_destroy_port(s);
- } while ((s = parent) != serio);
+
+ s = parent;
+ }
}
/*
- * Ok, no children left, now disconnect this port
+ * OK, no children left, now disconnect this port.
*/
device_release_driver(&serio->dev);
}
@@ -661,7 +696,7 @@ EXPORT_SYMBOL(serio_rescan);
void serio_reconnect(struct serio *serio)
{
- serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN);
+ serio_queue_event(serio, NULL, SERIO_RECONNECT_SUBTREE);
}
EXPORT_SYMBOL(serio_reconnect);
@@ -689,14 +724,16 @@ void serio_unregister_port(struct serio *serio)
EXPORT_SYMBOL(serio_unregister_port);
/*
- * Safely unregisters child port if one is present.
+ * Safely unregisters children ports if they are present.
*/
void serio_unregister_child_port(struct serio *serio)
{
+ struct serio *s, *next;
+
mutex_lock(&serio_mutex);
- if (serio->child) {
- serio_disconnect_port(serio->child);
- serio_destroy_port(serio->child);
+ list_for_each_entry_safe(s, next, &serio->children, child_node) {
+ serio_disconnect_port(s);
+ serio_destroy_port(s);
}
mutex_unlock(&serio_mutex);
}
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index 014248344763..a29a7812bd46 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -22,6 +22,37 @@ MODULE_DESCRIPTION("Generic support for sparse keymaps");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");
+static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
+ const struct key_entry *k)
+{
+ struct key_entry *key;
+ unsigned int idx = 0;
+
+ for (key = dev->keycode; key->type != KE_END; key++) {
+ if (key->type == KE_KEY) {
+ if (key == k)
+ break;
+ idx++;
+ }
+ }
+
+ return idx;
+}
+
+static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev,
+ unsigned int index)
+{
+ struct key_entry *key;
+ unsigned int key_cnt = 0;
+
+ for (key = dev->keycode; key->type != KE_END; key++)
+ if (key->type == KE_KEY)
+ if (key_cnt++ == index)
+ return key;
+
+ return NULL;
+}
+
/**
* sparse_keymap_entry_from_scancode - perform sparse keymap lookup
* @dev: Input device using sparse keymap
@@ -64,16 +95,36 @@ struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
}
EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
+static struct key_entry *sparse_keymap_locate(struct input_dev *dev,
+ const struct input_keymap_entry *ke)
+{
+ struct key_entry *key;
+ unsigned int scancode;
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+ key = sparse_keymap_entry_by_index(dev, ke->index);
+ else if (input_scancode_to_scalar(ke, &scancode) == 0)
+ key = sparse_keymap_entry_from_scancode(dev, scancode);
+ else
+ key = NULL;
+
+ return key;
+}
+
static int sparse_keymap_getkeycode(struct input_dev *dev,
- unsigned int scancode,
- unsigned int *keycode)
+ struct input_keymap_entry *ke)
{
const struct key_entry *key;
if (dev->keycode) {
- key = sparse_keymap_entry_from_scancode(dev, scancode);
+ key = sparse_keymap_locate(dev, ke);
if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
+ ke->keycode = key->keycode;
+ if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
+ ke->index =
+ sparse_keymap_get_key_index(dev, key);
+ ke->len = sizeof(key->code);
+ memcpy(ke->scancode, &key->code, sizeof(key->code));
return 0;
}
}
@@ -82,20 +133,19 @@ static int sparse_keymap_getkeycode(struct input_dev *dev,
}
static int sparse_keymap_setkeycode(struct input_dev *dev,
- unsigned int scancode,
- unsigned int keycode)
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
struct key_entry *key;
- int old_keycode;
if (dev->keycode) {
- key = sparse_keymap_entry_from_scancode(dev, scancode);
+ key = sparse_keymap_locate(dev, ke);
if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
- clear_bit(old_keycode, dev->keybit);
+ *old_keycode = key->keycode;
+ key->keycode = ke->keycode;
+ set_bit(ke->keycode, dev->keybit);
+ if (!sparse_keymap_entry_from_keycode(dev, *old_keycode))
+ clear_bit(*old_keycode, dev->keybit);
return 0;
}
}
@@ -159,15 +209,14 @@ int sparse_keymap_setup(struct input_dev *dev,
dev->keycode = map;
dev->keycodemax = map_size;
- dev->getkeycode = sparse_keymap_getkeycode;
- dev->setkeycode = sparse_keymap_setkeycode;
+ dev->getkeycode_new = sparse_keymap_getkeycode;
+ dev->setkeycode_new = sparse_keymap_setkeycode;
return 0;
err_out:
kfree(map);
return error;
-
}
EXPORT_SYMBOL(sparse_keymap_setup);
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
index effb49ea24aa..58a87755b936 100644
--- a/drivers/input/tablet/Kconfig
+++ b/drivers/input/tablet/Kconfig
@@ -49,6 +49,17 @@ config TABLET_USB_GTCO
To compile this driver as a module, choose M here: the
module will be called gtco.
+config TABLET_USB_HANWANG
+ tristate "Hanwang Art Master III tablet support (USB)"
+ depends on USB_ARCH_HAS_HCD
+ select USB
+ help
+ Say Y here if you want to use the USB version of the Hanwang Art
+ Master III tablet.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hanwang.
+
config TABLET_USB_KBTAB
tristate "KB Gear JamStudio tablet support (USB)"
depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile
index ce8b9a9cfa40..3f6c25220638 100644
--- a/drivers/input/tablet/Makefile
+++ b/drivers/input/tablet/Makefile
@@ -8,5 +8,6 @@ wacom-objs := wacom_wac.o wacom_sys.o
obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o
obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o
obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o
+obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o
obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o
diff --git a/drivers/input/tablet/hanwang.c b/drivers/input/tablet/hanwang.c
new file mode 100644
index 000000000000..6504b627b234
--- /dev/null
+++ b/drivers/input/tablet/hanwang.c
@@ -0,0 +1,446 @@
+/*
+ * USB Hanwang tablet support
+ *
+ * Copyright (c) 2010 Xing Wei <weixing@hanwang.com.cn>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+
+#define DRIVER_AUTHOR "Xing Wei <weixing@hanwang.com.cn>"
+#define DRIVER_DESC "USB Hanwang tablet driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_HANWANG 0x0b57
+#define HANWANG_TABLET_INT_CLASS 0x0003
+#define HANWANG_TABLET_INT_SUB_CLASS 0x0001
+#define HANWANG_TABLET_INT_PROTOCOL 0x0002
+
+#define ART_MASTER_PKGLEN_MAX 10
+
+/* device IDs */
+#define STYLUS_DEVICE_ID 0x02
+#define TOUCH_DEVICE_ID 0x03
+#define CURSOR_DEVICE_ID 0x06
+#define ERASER_DEVICE_ID 0x0A
+#define PAD_DEVICE_ID 0x0F
+
+/* match vendor and interface info */
+#define HANWANG_TABLET_DEVICE(vend, cl, sc, pr) \
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR \
+ | USB_DEVICE_ID_MATCH_INT_INFO, \
+ .idVendor = (vend), \
+ .bInterfaceClass = (cl), \
+ .bInterfaceSubClass = (sc), \
+ .bInterfaceProtocol = (pr)
+
+enum hanwang_tablet_type {
+ HANWANG_ART_MASTER_III,
+ HANWANG_ART_MASTER_HD,
+};
+
+struct hanwang {
+ unsigned char *data;
+ dma_addr_t data_dma;
+ struct input_dev *dev;
+ struct usb_device *usbdev;
+ struct urb *irq;
+ const struct hanwang_features *features;
+ unsigned int current_tool;
+ unsigned int current_id;
+ char name[64];
+ char phys[32];
+};
+
+struct hanwang_features {
+ unsigned short pid;
+ char *name;
+ enum hanwang_tablet_type type;
+ int pkg_len;
+ int max_x;
+ int max_y;
+ int max_tilt_x;
+ int max_tilt_y;
+ int max_pressure;
+};
+
+static const struct hanwang_features features_array[] = {
+ { 0x8528, "Hanwang Art Master III 0906", HANWANG_ART_MASTER_III,
+ ART_MASTER_PKGLEN_MAX, 0x5757, 0x3692, 0x3f, 0x7f, 2048 },
+ { 0x8529, "Hanwang Art Master III 0604", HANWANG_ART_MASTER_III,
+ ART_MASTER_PKGLEN_MAX, 0x3d84, 0x2672, 0x3f, 0x7f, 2048 },
+ { 0x852a, "Hanwang Art Master III 1308", HANWANG_ART_MASTER_III,
+ ART_MASTER_PKGLEN_MAX, 0x7f00, 0x4f60, 0x3f, 0x7f, 2048 },
+ { 0x8401, "Hanwang Art Master HD 5012", HANWANG_ART_MASTER_HD,
+ ART_MASTER_PKGLEN_MAX, 0x678e, 0x4150, 0x3f, 0x7f, 1024 },
+};
+
+static const int hw_eventtypes[] = {
+ EV_KEY, EV_ABS, EV_MSC,
+};
+
+static const int hw_absevents[] = {
+ ABS_X, ABS_Y, ABS_TILT_X, ABS_TILT_Y, ABS_WHEEL,
+ ABS_RX, ABS_RY, ABS_PRESSURE, ABS_MISC,
+};
+
+static const int hw_btnevents[] = {
+ BTN_STYLUS, BTN_STYLUS2, BTN_TOOL_PEN, BTN_TOOL_RUBBER,
+ BTN_TOOL_MOUSE, BTN_TOOL_FINGER,
+ BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8,
+};
+
+static const int hw_mscevents[] = {
+ MSC_SERIAL,
+};
+
+static void hanwang_parse_packet(struct hanwang *hanwang)
+{
+ unsigned char *data = hanwang->data;
+ struct input_dev *input_dev = hanwang->dev;
+ struct usb_device *dev = hanwang->usbdev;
+ enum hanwang_tablet_type type = hanwang->features->type;
+ int i;
+ u16 x, y, p;
+
+ switch (data[0]) {
+ case 0x02: /* data packet */
+ switch (data[1]) {
+ case 0x80: /* tool prox out */
+ hanwang->current_id = 0;
+ input_report_key(input_dev, hanwang->current_tool, 0);
+ break;
+
+ case 0xc2: /* first time tool prox in */
+ switch (data[3] & 0xf0) {
+ case 0x20: /* art_master III */
+ case 0x30: /* art_master_HD */
+ hanwang->current_id = STYLUS_DEVICE_ID;
+ hanwang->current_tool = BTN_TOOL_PEN;
+ input_report_key(input_dev, BTN_TOOL_PEN, 1);
+ break;
+ case 0xa0: /* art_master III */
+ case 0xb0: /* art_master_HD */
+ hanwang->current_id = ERASER_DEVICE_ID;
+ hanwang->current_tool = BTN_TOOL_RUBBER;
+ input_report_key(input_dev, BTN_TOOL_RUBBER, 1);
+ break;
+ default:
+ hanwang->current_id = 0;
+ dev_dbg(&dev->dev,
+ "unknown tablet tool %02x ", data[0]);
+ break;
+ }
+ break;
+
+ default: /* tool data packet */
+ x = (data[2] << 8) | data[3];
+ y = (data[4] << 8) | data[5];
+
+ switch (type) {
+ case HANWANG_ART_MASTER_III:
+ p = (data[6] << 3) |
+ ((data[7] & 0xc0) >> 5) |
+ (data[1] & 0x01);
+ break;
+
+ case HANWANG_ART_MASTER_HD:
+ p = (data[7] >> 6) | (data[6] << 2);
+ break;
+
+ default:
+ p = 0;
+ break;
+ }
+
+ input_report_abs(input_dev, ABS_X,
+ le16_to_cpup((__le16 *)&x));
+ input_report_abs(input_dev, ABS_Y,
+ le16_to_cpup((__le16 *)&y));
+ input_report_abs(input_dev, ABS_PRESSURE,
+ le16_to_cpup((__le16 *)&p));
+ input_report_abs(input_dev, ABS_TILT_X, data[7] & 0x3f);
+ input_report_abs(input_dev, ABS_TILT_Y, data[8] & 0x7f);
+ input_report_key(input_dev, BTN_STYLUS, data[1] & 0x02);
+ input_report_key(input_dev, BTN_STYLUS2, data[1] & 0x04);
+ break;
+ }
+ input_report_abs(input_dev, ABS_MISC, hanwang->current_id);
+ input_event(input_dev, EV_MSC, MSC_SERIAL,
+ hanwang->features->pid);
+ break;
+
+ case 0x0c:
+ /* roll wheel */
+ hanwang->current_id = PAD_DEVICE_ID;
+
+ switch (type) {
+ case HANWANG_ART_MASTER_III:
+ input_report_key(input_dev, BTN_TOOL_FINGER, data[1] ||
+ data[2] || data[3]);
+ input_report_abs(input_dev, ABS_WHEEL, data[1]);
+ input_report_key(input_dev, BTN_0, data[2]);
+ for (i = 0; i < 8; i++)
+ input_report_key(input_dev,
+ BTN_1 + i, data[3] & (1 << i));
+ break;
+
+ case HANWANG_ART_MASTER_HD:
+ input_report_key(input_dev, BTN_TOOL_FINGER, data[1] ||
+ data[2] || data[3] || data[4] ||
+ data[5] || data[6]);
+ input_report_abs(input_dev, ABS_RX,
+ ((data[1] & 0x1f) << 8) | data[2]);
+ input_report_abs(input_dev, ABS_RY,
+ ((data[3] & 0x1f) << 8) | data[4]);
+ input_report_key(input_dev, BTN_0, data[5] & 0x01);
+ for (i = 0; i < 4; i++) {
+ input_report_key(input_dev,
+ BTN_1 + i, data[5] & (1 << i));
+ input_report_key(input_dev,
+ BTN_5 + i, data[6] & (1 << i));
+ }
+ break;
+ }
+
+ input_report_abs(input_dev, ABS_MISC, hanwang->current_id);
+ input_event(input_dev, EV_MSC, MSC_SERIAL, 0xffffffff);
+ break;
+
+ default:
+ dev_dbg(&dev->dev, "error packet %02x ", data[0]);
+ break;
+ }
+
+ input_sync(input_dev);
+}
+
+static void hanwang_irq(struct urb *urb)
+{
+ struct hanwang *hanwang = urb->context;
+ struct usb_device *dev = hanwang->usbdev;
+ int retval;
+
+ switch (urb->status) {
+ case 0:
+ /* success */;
+ hanwang_parse_packet(hanwang);
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dev_err(&dev->dev, "%s - urb shutting down with status: %d",
+ __func__, urb->status);
+ return;
+ default:
+ dev_err(&dev->dev, "%s - nonzero urb status received: %d",
+ __func__, urb->status);
+ break;
+ }
+
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ dev_err(&dev->dev, "%s - usb_submit_urb failed with result %d",
+ __func__, retval);
+}
+
+static int hanwang_open(struct input_dev *dev)
+{
+ struct hanwang *hanwang = input_get_drvdata(dev);
+
+ hanwang->irq->dev = hanwang->usbdev;
+ if (usb_submit_urb(hanwang->irq, GFP_KERNEL))
+ return -EIO;
+
+ return 0;
+}
+
+static void hanwang_close(struct input_dev *dev)
+{
+ struct hanwang *hanwang = input_get_drvdata(dev);
+
+ usb_kill_urb(hanwang->irq);
+}
+
+static bool get_features(struct usb_device *dev, struct hanwang *hanwang)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(features_array); i++) {
+ if (le16_to_cpu(dev->descriptor.idProduct) ==
+ features_array[i].pid) {
+ hanwang->features = &features_array[i];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static int hanwang_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_endpoint_descriptor *endpoint;
+ struct hanwang *hanwang;
+ struct input_dev *input_dev;
+ int error;
+ int i;
+
+ hanwang = kzalloc(sizeof(struct hanwang), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!hanwang || !input_dev) {
+ error = -ENOMEM;
+ goto fail1;
+ }
+
+ if (!get_features(dev, hanwang)) {
+ error = -ENXIO;
+ goto fail1;
+ }
+
+ hanwang->data = usb_alloc_coherent(dev, hanwang->features->pkg_len,
+ GFP_KERNEL, &hanwang->data_dma);
+ if (!hanwang->data) {
+ error = -ENOMEM;
+ goto fail1;
+ }
+
+ hanwang->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!hanwang->irq) {
+ error = -ENOMEM;
+ goto fail2;
+ }
+
+ hanwang->usbdev = dev;
+ hanwang->dev = input_dev;
+
+ usb_make_path(dev, hanwang->phys, sizeof(hanwang->phys));
+ strlcat(hanwang->phys, "/input0", sizeof(hanwang->phys));
+
+ strlcpy(hanwang->name, hanwang->features->name, sizeof(hanwang->name));
+ input_dev->name = hanwang->name;
+ input_dev->phys = hanwang->phys;
+ usb_to_input_id(dev, &input_dev->id);
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, hanwang);
+
+ input_dev->open = hanwang_open;
+ input_dev->close = hanwang_close;
+
+ for (i = 0; i < ARRAY_SIZE(hw_eventtypes); ++i)
+ __set_bit(hw_eventtypes[i], input_dev->evbit);
+
+ for (i = 0; i < ARRAY_SIZE(hw_absevents); ++i)
+ __set_bit(hw_absevents[i], input_dev->absbit);
+
+ for (i = 0; i < ARRAY_SIZE(hw_btnevents); ++i)
+ __set_bit(hw_btnevents[i], input_dev->keybit);
+
+ for (i = 0; i < ARRAY_SIZE(hw_mscevents); ++i)
+ __set_bit(hw_mscevents[i], input_dev->mscbit);
+
+ input_set_abs_params(input_dev, ABS_X,
+ 0, hanwang->features->max_x, 4, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ 0, hanwang->features->max_y, 4, 0);
+ input_set_abs_params(input_dev, ABS_TILT_X,
+ 0, hanwang->features->max_tilt_x, 0, 0);
+ input_set_abs_params(input_dev, ABS_TILT_Y,
+ 0, hanwang->features->max_tilt_y, 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ 0, hanwang->features->max_pressure, 0, 0);
+
+ endpoint = &intf->cur_altsetting->endpoint[0].desc;
+ usb_fill_int_urb(hanwang->irq, dev,
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ hanwang->data, hanwang->features->pkg_len,
+ hanwang_irq, hanwang, endpoint->bInterval);
+ hanwang->irq->transfer_dma = hanwang->data_dma;
+ hanwang->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ error = input_register_device(hanwang->dev);
+ if (error)
+ goto fail3;
+
+ usb_set_intfdata(intf, hanwang);
+
+ return 0;
+
+ fail3: usb_free_urb(hanwang->irq);
+ fail2: usb_free_coherent(dev, hanwang->features->pkg_len,
+ hanwang->data, hanwang->data_dma);
+ fail1: input_free_device(input_dev);
+ kfree(hanwang);
+ return error;
+
+}
+
+static void hanwang_disconnect(struct usb_interface *intf)
+{
+ struct hanwang *hanwang = usb_get_intfdata(intf);
+
+ input_unregister_device(hanwang->dev);
+ usb_free_urb(hanwang->irq);
+ usb_free_coherent(interface_to_usbdev(intf),
+ hanwang->features->pkg_len, hanwang->data,
+ hanwang->data_dma);
+ kfree(hanwang);
+ usb_set_intfdata(intf, NULL);
+}
+
+static const struct usb_device_id hanwang_ids[] = {
+ { HANWANG_TABLET_DEVICE(USB_VENDOR_ID_HANWANG, HANWANG_TABLET_INT_CLASS,
+ HANWANG_TABLET_INT_SUB_CLASS, HANWANG_TABLET_INT_PROTOCOL) },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, hanwang_ids);
+
+static struct usb_driver hanwang_driver = {
+ .name = "hanwang",
+ .probe = hanwang_probe,
+ .disconnect = hanwang_disconnect,
+ .id_table = hanwang_ids,
+};
+
+static int __init hanwang_init(void)
+{
+ return usb_register(&hanwang_driver);
+}
+
+static void __exit hanwang_exit(void)
+{
+ usb_deregister(&hanwang_driver);
+}
+
+module_init(hanwang_init);
+module_exit(hanwang_exit);
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
index 284dfaab6b8c..de5adb109030 100644
--- a/drivers/input/tablet/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -118,6 +118,7 @@ struct wacom {
extern const struct usb_device_id wacom_ids[];
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
+void wacom_setup_device_quirks(struct wacom_features *features);
void wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac);
#endif
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index b35876ee6908..fc381498b798 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -120,14 +120,16 @@ static int wacom_open(struct input_dev *dev)
out:
mutex_unlock(&wacom->lock);
- if (retval)
- usb_autopm_put_interface(wacom->intf);
+ usb_autopm_put_interface(wacom->intf);
return retval;
}
static void wacom_close(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
+ int autopm_error;
+
+ autopm_error = usb_autopm_get_interface(wacom->intf);
mutex_lock(&wacom->lock);
usb_kill_urb(wacom->irq);
@@ -135,7 +137,8 @@ static void wacom_close(struct input_dev *dev)
wacom->intf->needs_remote_wakeup = 0;
mutex_unlock(&wacom->lock);
- usb_autopm_put_interface(wacom->intf);
+ if (!autopm_error)
+ usb_autopm_put_interface(wacom->intf);
}
static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc,
@@ -196,17 +199,30 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
features->pktlen = WACOM_PKGLEN_TPC2FG;
features->device_type = BTN_TOOL_TRIPLETAP;
}
- features->x_max =
- get_unaligned_le16(&report[i + 3]);
- features->x_phy =
- get_unaligned_le16(&report[i + 6]);
- features->unit = report[i + 9];
- features->unitExpo = report[i + 11];
- i += 12;
+ if (features->type == BAMBOO_PT) {
+ /* need to reset back */
+ features->pktlen = WACOM_PKGLEN_BBTOUCH;
+ features->device_type = BTN_TOOL_TRIPLETAP;
+ features->x_phy =
+ get_unaligned_le16(&report[i + 5]);
+ features->x_max =
+ get_unaligned_le16(&report[i + 8]);
+ i += 15;
+ } else {
+ features->x_max =
+ get_unaligned_le16(&report[i + 3]);
+ features->x_phy =
+ get_unaligned_le16(&report[i + 6]);
+ features->unit = report[i + 9];
+ features->unitExpo = report[i + 11];
+ i += 12;
+ }
} else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
+ if (features->type == BAMBOO_PT)
+ features->pktlen = WACOM_PKGLEN_BBFUN;
features->device_type = BTN_TOOL_PEN;
features->x_max =
get_unaligned_le16(&report[i + 3]);
@@ -235,6 +251,15 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
features->y_phy =
get_unaligned_le16(&report[i + 6]);
i += 7;
+ } else if (features->type == BAMBOO_PT) {
+ /* need to reset back */
+ features->pktlen = WACOM_PKGLEN_BBTOUCH;
+ features->device_type = BTN_TOOL_TRIPLETAP;
+ features->y_phy =
+ get_unaligned_le16(&report[i + 3]);
+ features->y_max =
+ get_unaligned_le16(&report[i + 6]);
+ i += 12;
} else {
features->y_max =
features->x_max;
@@ -246,6 +271,8 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
+ if (features->type == BAMBOO_PT)
+ features->pktlen = WACOM_PKGLEN_BBFUN;
features->device_type = BTN_TOOL_PEN;
features->y_max =
get_unaligned_le16(&report[i + 3]);
@@ -296,8 +323,9 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
if (!rep_data)
return error;
- /* ask to report tablet data if it is 2FGT or not a Tablet PC */
- if (features->device_type == BTN_TOOL_TRIPLETAP) {
+ /* ask to report tablet data if it is 2FGT Tablet PC or
+ * not a Tablet PC */
+ if (features->type == TABLETPC2FG) {
do {
rep_data[0] = 3;
rep_data[1] = 4;
@@ -309,7 +337,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
WAC_HID_FEATURE_REPORT, report_id,
rep_data, 3);
} while ((error < 0 || rep_data[1] != 4) && limit++ < 5);
- } else if (features->type != TABLETPC && features->type != TABLETPC2FG) {
+ } else if (features->type != TABLETPC) {
do {
rep_data[0] = 2;
rep_data[1] = 2;
@@ -334,11 +362,16 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
struct usb_host_interface *interface = intf->cur_altsetting;
struct hid_descriptor *hid_desc;
- /* default device to penabled */
+ /* default features */
features->device_type = BTN_TOOL_PEN;
-
- /* only Tablet PCs need to retrieve the info */
- if ((features->type != TABLETPC) && (features->type != TABLETPC2FG))
+ features->x_fuzz = 4;
+ features->y_fuzz = 4;
+ features->pressure_fuzz = 0;
+ features->distance_fuzz = 0;
+
+ /* only Tablet PCs and Bamboo P&T need to retrieve the info */
+ if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
+ (features->type != BAMBOO_PT))
goto out;
if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
@@ -353,12 +386,6 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
if (error)
goto out;
- /* touch device found but size is not defined. use default */
- if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) {
- features->x_max = 1023;
- features->y_max = 1023;
- }
-
out:
return error;
}
@@ -494,9 +521,11 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (error)
goto fail2;
+ wacom_setup_device_quirks(features);
+
strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
- if (features->type == TABLETPC || features->type == TABLETPC2FG) {
+ if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
/* Append the device type to the name */
strlcat(wacom_wac->name,
features->device_type == BTN_TOOL_PEN ?
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 47fd7a041c52..b3252ef1e279 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -857,6 +857,134 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
return retval;
}
+static int wacom_bpt_touch(struct wacom_wac *wacom)
+{
+ struct wacom_features *features = &wacom->features;
+ struct input_dev *input = wacom->input;
+ unsigned char *data = wacom->data;
+ int sp = 0, sx = 0, sy = 0, count = 0;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ int p = data[9 * i + 2];
+ input_mt_slot(input, i);
+ /*
+ * Touch events need to be disabled while stylus is
+ * in proximity because user's hand is resting on touchpad
+ * and sending unwanted events. User expects tablet buttons
+ * to continue working though.
+ */
+ if (p && !wacom->shared->stylus_in_proximity) {
+ int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff;
+ int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff;
+ if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
+ x <<= 5;
+ y <<= 5;
+ }
+ input_report_abs(input, ABS_MT_PRESSURE, p);
+ input_report_abs(input, ABS_MT_POSITION_X, x);
+ input_report_abs(input, ABS_MT_POSITION_Y, y);
+ if (wacom->id[i] < 0)
+ wacom->id[i] = wacom->trk_id++ & MAX_TRACKING_ID;
+ if (!count++)
+ sp = p, sx = x, sy = y;
+ } else {
+ wacom->id[i] = -1;
+ }
+ input_report_abs(input, ABS_MT_TRACKING_ID, wacom->id[i]);
+ }
+
+ input_report_key(input, BTN_TOUCH, count > 0);
+ input_report_key(input, BTN_TOOL_FINGER, count == 1);
+ input_report_key(input, BTN_TOOL_DOUBLETAP, count == 2);
+
+ input_report_abs(input, ABS_PRESSURE, sp);
+ input_report_abs(input, ABS_X, sx);
+ input_report_abs(input, ABS_Y, sy);
+
+ input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
+ input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
+ input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
+ input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0);
+
+ input_sync(input);
+
+ return 0;
+}
+
+static int wacom_bpt_pen(struct wacom_wac *wacom)
+{
+ struct input_dev *input = wacom->input;
+ unsigned char *data = wacom->data;
+ int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
+
+ /*
+ * Similar to Graphire protocol, data[1] & 0x20 is proximity and
+ * data[1] & 0x18 is tool ID. 0x30 is safety check to ignore
+ * 2 unused tool ID's.
+ */
+ prox = (data[1] & 0x30) == 0x30;
+
+ /*
+ * All reports shared between PEN and RUBBER tool must be
+ * forced to a known starting value (zero) when transitioning to
+ * out-of-prox.
+ *
+ * If not reset then, to userspace, it will look like lost events
+ * if new tool comes in-prox with same values as previous tool sent.
+ *
+ * Hardware does report zero in most out-of-prox cases but not all.
+ */
+ if (prox) {
+ if (!wacom->shared->stylus_in_proximity) {
+ if (data[1] & 0x08) {
+ wacom->tool[0] = BTN_TOOL_RUBBER;
+ wacom->id[0] = ERASER_DEVICE_ID;
+ } else {
+ wacom->tool[0] = BTN_TOOL_PEN;
+ wacom->id[0] = STYLUS_DEVICE_ID;
+ }
+ wacom->shared->stylus_in_proximity = true;
+ }
+ x = le16_to_cpup((__le16 *)&data[2]);
+ y = le16_to_cpup((__le16 *)&data[4]);
+ p = le16_to_cpup((__le16 *)&data[6]);
+ d = data[8];
+ pen = data[1] & 0x01;
+ btn1 = data[1] & 0x02;
+ btn2 = data[1] & 0x04;
+ }
+
+ input_report_key(input, BTN_TOUCH, pen);
+ input_report_key(input, BTN_STYLUS, btn1);
+ input_report_key(input, BTN_STYLUS2, btn2);
+
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_PRESSURE, p);
+ input_report_abs(input, ABS_DISTANCE, d);
+
+ if (!prox) {
+ wacom->id[0] = 0;
+ wacom->shared->stylus_in_proximity = false;
+ }
+
+ input_report_key(input, wacom->tool[0], prox); /* PEN or RUBBER */
+ input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
+
+ return 1;
+}
+
+static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
+{
+ if (len == WACOM_PKGLEN_BBTOUCH)
+ return wacom_bpt_touch(wacom);
+ else if (len == WACOM_PKGLEN_BBFUN)
+ return wacom_bpt_pen(wacom);
+
+ return 0;
+}
+
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
{
bool sync;
@@ -902,6 +1030,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
sync = wacom_tpc_irq(wacom_wac, len);
break;
+ case BAMBOO_PT:
+ sync = wacom_bpt_irq(wacom_wac, len);
+ break;
+
default:
sync = false;
break;
@@ -911,26 +1043,17 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
input_sync(wacom_wac->input);
}
-static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
+static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
{
struct input_dev *input_dev = wacom_wac->input;
input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
- input_set_capability(input_dev, EV_REL, REL_WHEEL);
-
- __set_bit(BTN_LEFT, input_dev->keybit);
- __set_bit(BTN_RIGHT, input_dev->keybit);
- __set_bit(BTN_MIDDLE, input_dev->keybit);
- __set_bit(BTN_SIDE, input_dev->keybit);
- __set_bit(BTN_EXTRA, input_dev->keybit);
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
- __set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
__set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
__set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
__set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
- __set_bit(BTN_TOOL_LENS, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
@@ -939,10 +1062,55 @@ static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
+}
+
+static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
+{
+ struct input_dev *input_dev = wacom_wac->input;
+
+ input_set_capability(input_dev, EV_REL, REL_WHEEL);
+
+ wacom_setup_cintiq(wacom_wac);
+
+ __set_bit(BTN_LEFT, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+ __set_bit(BTN_MIDDLE, input_dev->keybit);
+ __set_bit(BTN_SIDE, input_dev->keybit);
+ __set_bit(BTN_EXTRA, input_dev->keybit);
+ __set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
+ __set_bit(BTN_TOOL_LENS, input_dev->keybit);
+
input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
}
+void wacom_setup_device_quirks(struct wacom_features *features)
+{
+
+ /* touch device found but size is not defined. use default */
+ if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) {
+ features->x_max = 1023;
+ features->y_max = 1023;
+ }
+
+ /* these device have multiple inputs */
+ if (features->type == TABLETPC || features->type == TABLETPC2FG ||
+ features->type == BAMBOO_PT)
+ features->quirks |= WACOM_QUIRK_MULTI_INPUT;
+
+ /* quirks for bamboo touch */
+ if (features->type == BAMBOO_PT &&
+ features->device_type == BTN_TOOL_TRIPLETAP) {
+ features->x_max <<= 5;
+ features->y_max <<= 5;
+ features->x_fuzz <<= 5;
+ features->y_fuzz <<= 5;
+ features->pressure_max = 256;
+ features->pressure_fuzz = 16;
+ features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
+ }
+}
+
void wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac)
{
@@ -953,9 +1121,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOUCH, input_dev->keybit);
- input_set_abs_params(input_dev, ABS_X, 0, features->x_max, 4, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, 4, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, 0, 0);
+ input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
+ features->x_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
+ features->y_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
+ features->pressure_fuzz, 0);
__set_bit(ABS_MISC, input_dev->absbit);
@@ -1005,9 +1176,19 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_9, input_dev->keybit);
/* fall through */
+ case CINTIQ:
+ for (i = 0; i < 8; i++)
+ __set_bit(BTN_0 + i, input_dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
+ input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
+ input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+ wacom_setup_cintiq(wacom_wac);
+ break;
+
case INTUOS3:
case INTUOS3L:
- case CINTIQ:
__set_bit(BTN_4, input_dev->keybit);
__set_bit(BTN_5, input_dev->keybit);
__set_bit(BTN_6, input_dev->keybit);
@@ -1078,6 +1259,38 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
case PENPARTNER:
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
break;
+
+ case BAMBOO_PT:
+ __clear_bit(ABS_MISC, input_dev->absbit);
+
+ if (features->device_type == BTN_TOOL_TRIPLETAP) {
+ __set_bit(BTN_LEFT, input_dev->keybit);
+ __set_bit(BTN_FORWARD, input_dev->keybit);
+ __set_bit(BTN_BACK, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+
+ __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+
+ input_mt_create_slots(input_dev, 2);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, features->x_max,
+ features->x_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, features->y_max,
+ features->y_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+ 0, features->pressure_max,
+ features->pressure_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
+ MAX_TRACKING_ID, 0, 0);
+ } else if (features->device_type == BTN_TOOL_PEN) {
+ __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+ __set_bit(BTN_TOOL_PEN, input_dev->keybit);
+ __set_bit(BTN_STYLUS, input_dev->keybit);
+ __set_bit(BTN_STYLUS2, input_dev->keybit);
+ }
+ break;
}
}
@@ -1215,6 +1428,14 @@ static const struct wacom_features wacom_features_0xE3 =
{ "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG };
static const struct wacom_features wacom_features_0x47 =
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS };
+static struct wacom_features wacom_features_0xD0 =
+ { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD1 =
+ { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD2 =
+ { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD3 =
+ { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT };
#define USB_DEVICE_WACOM(prod) \
USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \
@@ -1279,6 +1500,10 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xC6) },
{ USB_DEVICE_WACOM(0xC7) },
{ USB_DEVICE_WACOM(0xCE) },
+ { USB_DEVICE_WACOM(0xD0) },
+ { USB_DEVICE_WACOM(0xD1) },
+ { USB_DEVICE_WACOM(0xD2) },
+ { USB_DEVICE_WACOM(0xD3) },
{ USB_DEVICE_WACOM(0xF0) },
{ USB_DEVICE_WACOM(0xCC) },
{ USB_DEVICE_WACOM(0x90) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 99e1a54cd305..00ca01541d89 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -21,6 +21,7 @@
#define WACOM_PKGLEN_INTUOS 10
#define WACOM_PKGLEN_TPC1FG 5
#define WACOM_PKGLEN_TPC2FG 14
+#define WACOM_PKGLEN_BBTOUCH 20
/* device IDs */
#define STYLUS_DEVICE_ID 0x02
@@ -37,6 +38,13 @@
#define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13
+/* device quirks */
+#define WACOM_QUIRK_MULTI_INPUT 0x0001
+#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002
+
+/* largest reported tracking id */
+#define MAX_TRACKING_ID 0xfff
+
enum {
PENPARTNER = 0,
GRAPHIRE,
@@ -44,6 +52,7 @@ enum {
PTU,
PL,
DTU,
+ BAMBOO_PT,
INTUOS,
INTUOS3S,
INTUOS3,
@@ -73,6 +82,11 @@ struct wacom_features {
int y_phy;
unsigned char unit;
unsigned char unitExpo;
+ int x_fuzz;
+ int y_fuzz;
+ int pressure_fuzz;
+ int distance_fuzz;
+ unsigned quirks;
};
struct wacom_shared {
@@ -86,6 +100,7 @@ struct wacom_wac {
int id[3];
__u32 serial[2];
int last_finger;
+ int trk_id;
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 0069d9703fda..0ea361f23fa7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -98,6 +98,18 @@ config TOUCHSCREEN_BITSY
To compile this driver as a module, choose M here: the
module will be called h3600_ts_input.
+config TOUCHSCREEN_BU21013
+ tristate "BU21013 based touch panel controllers"
+ depends on I2C
+ help
+ Say Y here if you have a bu21013 touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bu21013_ts.
+
config TOUCHSCREEN_CY8CTMG110
tristate "cy8ctmg110 touchscreen"
depends on I2C
@@ -214,6 +226,16 @@ config TOUCHSCREEN_WACOM_W8001
To compile this driver as a module, choose M here: the
module will be called wacom_w8001.
+config TOUCHSCREEN_LPC32XX
+ tristate "LPC32XX touchscreen controller"
+ depends on ARCH_LPC32XX
+ help
+ Say Y here if you have a LPC32XX device and want
+ to support the built-in touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called lpc32xx_ts.
+
config TOUCHSCREEN_MCS5000
tristate "MELFAS MCS-5000 touchscreen"
depends on I2C
@@ -250,6 +272,18 @@ config TOUCHSCREEN_INEXIO
To compile this driver as a module, choose M here: the
module will be called inexio.
+config TOUCHSCREEN_INTEL_MID
+ tristate "Intel MID platform resistive touchscreen"
+ depends on INTEL_SCU_IPC
+ help
+ Say Y here if you have a Intel MID based touchscreen in
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called intel_mid_touch.
+
config TOUCHSCREEN_MK712
tristate "ICS MicroClock MK712 touchscreen"
help
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 28217e1dcafd..99b353c4e9ae 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
@@ -23,6 +24,8 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
+obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
+obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index 5f0221cffef9..a1952fcc083e 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -191,13 +191,12 @@ struct ad7877 {
struct spi_message msg;
struct mutex mutex;
- unsigned disabled:1; /* P: mutex */
- unsigned gpio3:1; /* P: mutex */
- unsigned gpio4:1; /* P: mutex */
+ bool disabled; /* P: mutex */
+ bool gpio3; /* P: mutex */
+ bool gpio4; /* P: mutex */
spinlock_t lock;
struct timer_list timer; /* P: lock */
- unsigned pending:1; /* P: lock */
/*
* DMA (thus cache coherency maintenance) requires the
@@ -206,8 +205,8 @@ struct ad7877 {
u16 conversion_data[AD7877_NR_SENSE] ____cacheline_aligned;
};
-static int gpio3;
-module_param(gpio3, int, 0);
+static bool gpio3;
+module_param(gpio3, bool, 0);
MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
/*
@@ -230,6 +229,7 @@ static int ad7877_read(struct spi_device *spi, u16 reg)
AD7877_READADD(reg));
req->xfer[0].tx_buf = &req->command;
req->xfer[0].len = 2;
+ req->xfer[0].cs_change = 1;
req->xfer[1].rx_buf = &req->sample;
req->xfer[1].len = 2;
@@ -295,20 +295,25 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
req->xfer[0].tx_buf = &req->reset;
req->xfer[0].len = 2;
+ req->xfer[0].cs_change = 1;
req->xfer[1].tx_buf = &req->ref_on;
req->xfer[1].len = 2;
req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+ req->xfer[1].cs_change = 1;
req->xfer[2].tx_buf = &req->command;
req->xfer[2].len = 2;
req->xfer[2].delay_usecs = ts->vref_delay_usecs;
+ req->xfer[2].cs_change = 1;
req->xfer[3].rx_buf = &req->sample;
req->xfer[3].len = 2;
+ req->xfer[3].cs_change = 1;
req->xfer[4].tx_buf = &ts->cmd_crtl2; /*REF OFF*/
req->xfer[4].len = 2;
+ req->xfer[4].cs_change = 1;
req->xfer[5].tx_buf = &ts->cmd_crtl1; /*DEFAULT*/
req->xfer[5].len = 2;
@@ -327,7 +332,7 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
return status ? : sample;
}
-static void ad7877_rx(struct ad7877 *ts)
+static int ad7877_process_data(struct ad7877 *ts)
{
struct input_dev *input_dev = ts->input;
unsigned Rt;
@@ -354,11 +359,25 @@ static void ad7877_rx(struct ad7877 *ts)
Rt /= z1;
Rt = (Rt + 2047) >> 12;
+ /*
+ * Sample found inconsistent, pressure is beyond
+ * the maximum. Don't report it to user space.
+ */
+ if (Rt > ts->pressure_max)
+ return -EINVAL;
+
+ if (!timer_pending(&ts->timer))
+ input_report_key(input_dev, BTN_TOUCH, 1);
+
input_report_abs(input_dev, ABS_X, x);
input_report_abs(input_dev, ABS_Y, y);
input_report_abs(input_dev, ABS_PRESSURE, Rt);
input_sync(input_dev);
+
+ return 0;
}
+
+ return -EINVAL;
}
static inline void ad7877_ts_event_release(struct ad7877 *ts)
@@ -366,72 +385,56 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
struct input_dev *input_dev = ts->input;
input_report_abs(input_dev, ABS_PRESSURE, 0);
+ input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
}
static void ad7877_timer(unsigned long handle)
{
struct ad7877 *ts = (void *)handle;
+ unsigned long flags;
+ spin_lock_irqsave(&ts->lock, flags);
ad7877_ts_event_release(ts);
+ spin_unlock_irqrestore(&ts->lock, flags);
}
static irqreturn_t ad7877_irq(int irq, void *handle)
{
struct ad7877 *ts = handle;
unsigned long flags;
- int status;
+ int error;
- /*
- * The repeated conversion sequencer controlled by TMR kicked off
- * too fast. We ignore the last and process the sample sequence
- * currently in the queue. It can't be older than 9.4ms, and we
- * need to avoid that ts->msg doesn't get issued twice while in work.
- */
+ error = spi_sync(ts->spi, &ts->msg);
+ if (error) {
+ dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
+ goto out;
+ }
spin_lock_irqsave(&ts->lock, flags);
- if (!ts->pending) {
- ts->pending = 1;
-
- status = spi_async(ts->spi, &ts->msg);
- if (status)
- dev_err(&ts->spi->dev, "spi_sync --> %d\n", status);
- }
+ error = ad7877_process_data(ts);
+ if (!error)
+ mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
spin_unlock_irqrestore(&ts->lock, flags);
+out:
return IRQ_HANDLED;
}
-static void ad7877_callback(void *_ts)
-{
- struct ad7877 *ts = _ts;
-
- spin_lock_irq(&ts->lock);
-
- ad7877_rx(ts);
- ts->pending = 0;
- mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
-
- spin_unlock_irq(&ts->lock);
-}
-
static void ad7877_disable(struct ad7877 *ts)
{
mutex_lock(&ts->mutex);
if (!ts->disabled) {
- ts->disabled = 1;
+ ts->disabled = true;
disable_irq(ts->spi->irq);
- /* Wait for spi_async callback */
- while (ts->pending)
- msleep(1);
-
if (del_timer_sync(&ts->timer))
ad7877_ts_event_release(ts);
}
- /* we know the chip's in lowpower mode since we always
+ /*
+ * We know the chip's in lowpower mode since we always
* leave it that way after every request
*/
@@ -443,7 +446,7 @@ static void ad7877_enable(struct ad7877 *ts)
mutex_lock(&ts->mutex);
if (ts->disabled) {
- ts->disabled = 0;
+ ts->disabled = false;
enable_irq(ts->spi->irq);
}
@@ -453,7 +456,7 @@ static void ad7877_enable(struct ad7877 *ts)
#define SHOW(name) static ssize_t \
name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
- struct ad7877 *ts = dev_get_drvdata(dev); \
+ struct ad7877 *ts = dev_get_drvdata(dev); \
ssize_t v = ad7877_read_adc(ts->spi, \
AD7877_READ_CHAN(name)); \
if (v < 0) \
@@ -473,7 +476,7 @@ SHOW(temp2)
static ssize_t ad7877_disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad7877 *ts = dev_get_drvdata(dev);
+ struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->disabled);
}
@@ -503,7 +506,7 @@ static DEVICE_ATTR(disable, 0664, ad7877_disable_show, ad7877_disable_store);
static ssize_t ad7877_dac_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad7877 *ts = dev_get_drvdata(dev);
+ struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->dac);
}
@@ -533,7 +536,7 @@ static DEVICE_ATTR(dac, 0664, ad7877_dac_show, ad7877_dac_store);
static ssize_t ad7877_gpio3_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad7877 *ts = dev_get_drvdata(dev);
+ struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->gpio3);
}
@@ -564,7 +567,7 @@ static DEVICE_ATTR(gpio3, 0664, ad7877_gpio3_show, ad7877_gpio3_store);
static ssize_t ad7877_gpio4_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad7877 *ts = dev_get_drvdata(dev);
+ struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->gpio4);
}
@@ -597,16 +600,35 @@ static struct attribute *ad7877_attributes[] = {
&dev_attr_temp2.attr,
&dev_attr_aux1.attr,
&dev_attr_aux2.attr,
+ &dev_attr_aux3.attr,
&dev_attr_bat1.attr,
&dev_attr_bat2.attr,
&dev_attr_disable.attr,
&dev_attr_dac.attr,
+ &dev_attr_gpio3.attr,
&dev_attr_gpio4.attr,
NULL
};
+static mode_t ad7877_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ mode_t mode = attr->mode;
+
+ if (attr == &dev_attr_aux3.attr) {
+ if (gpio3)
+ mode = 0;
+ } else if (attr == &dev_attr_gpio3.attr) {
+ if (!gpio3)
+ mode = 0;
+ }
+
+ return mode;
+}
+
static const struct attribute_group ad7877_attr_group = {
- .attrs = ad7877_attributes,
+ .is_visible = ad7877_attr_is_visible,
+ .attrs = ad7877_attributes,
};
static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
@@ -635,22 +657,25 @@ static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
spi_message_init(m);
- m->complete = ad7877_callback;
m->context = ts;
ts->xfer[0].tx_buf = &ts->cmd_crtl1;
ts->xfer[0].len = 2;
+ ts->xfer[0].cs_change = 1;
spi_message_add_tail(&ts->xfer[0], m);
ts->xfer[1].tx_buf = &ts->cmd_dummy; /* Send ZERO */
ts->xfer[1].len = 2;
+ ts->xfer[1].cs_change = 1;
spi_message_add_tail(&ts->xfer[1], m);
- for (i = 0; i < 11; i++) {
+ for (i = 0; i < AD7877_NR_SENSE; i++) {
ts->xfer[i + 2].rx_buf = &ts->conversion_data[AD7877_SEQ_YPOS + i];
ts->xfer[i + 2].len = 2;
+ if (i < (AD7877_NR_SENSE - 1))
+ ts->xfer[i + 2].cs_change = 1;
spi_message_add_tail(&ts->xfer[i + 2], m);
}
}
@@ -718,6 +743,8 @@ static int __devinit ad7877_probe(struct spi_device *spi)
input_dev->phys = ts->phys;
input_dev->dev.parent = &spi->dev;
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(ABS_X, input_dev->absbit);
__set_bit(ABS_Y, input_dev->absbit);
@@ -752,8 +779,9 @@ static int __devinit ad7877_probe(struct spi_device *spi)
/* Request AD7877 /DAV GPIO interrupt */
- err = request_irq(spi->irq, ad7877_irq, IRQF_TRIGGER_FALLING,
- spi->dev.driver->name, ts);
+ err = request_threaded_irq(spi->irq, NULL, ad7877_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ spi->dev.driver->name, ts);
if (err) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
goto err_free_mem;
@@ -763,20 +791,12 @@ static int __devinit ad7877_probe(struct spi_device *spi)
if (err)
goto err_free_irq;
- err = device_create_file(&spi->dev,
- gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
- if (err)
- goto err_remove_attr_group;
-
err = input_register_device(input_dev);
if (err)
- goto err_remove_attr;
+ goto err_remove_attr_group;
return 0;
-err_remove_attr:
- device_remove_file(&spi->dev,
- gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
err_remove_attr_group:
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
err_free_irq:
@@ -790,11 +810,9 @@ err_free_mem:
static int __devexit ad7877_remove(struct spi_device *spi)
{
- struct ad7877 *ts = dev_get_drvdata(&spi->dev);
+ struct ad7877 *ts = dev_get_drvdata(&spi->dev);
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
- device_remove_file(&spi->dev,
- gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
ad7877_disable(ts);
free_irq(ts->spi->irq, ts);
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 16031933a8f6..14ea54b78e46 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -17,9 +17,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/types.h>
#include <linux/hwmon.h>
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@@ -52,22 +54,23 @@
* files.
*/
-#define TS_POLL_DELAY (1 * 1000000) /* ns delay before the first sample */
-#define TS_POLL_PERIOD (5 * 1000000) /* ns delay between samples */
+#define TS_POLL_DELAY 1 /* ms delay before the first sample */
+#define TS_POLL_PERIOD 5 /* ms delay between samples */
/* this driver doesn't aim at the peak continuous sample rate */
#define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
struct ts_event {
- /* For portability, we can't read 12 bit values using SPI (which
- * would make the controller deliver them as native byteorder u16
+ /*
+ * For portability, we can't read 12 bit values using SPI (which
+ * would make the controller deliver them as native byte order u16
* with msbs zeroed). Instead, we read them as two 8-bit values,
* *** WHICH NEED BYTESWAPPING *** and range adjustment.
*/
u16 x;
u16 y;
u16 z1, z2;
- int ignore;
+ bool ignore;
u8 x_buf[3];
u8 y_buf[3];
};
@@ -110,8 +113,11 @@ struct ads7846 {
struct spi_transfer xfer[18];
struct spi_message msg[5];
- struct spi_message *last_msg;
- int msg_idx;
+ int msg_count;
+ wait_queue_head_t wait;
+
+ bool pendown;
+
int read_cnt;
int read_rep;
int last_read;
@@ -122,14 +128,10 @@ struct ads7846 {
u16 penirq_recheck_delay_usecs;
- spinlock_t lock;
- struct hrtimer timer;
- unsigned pendown:1; /* P: lock */
- unsigned pending:1; /* P: lock */
-// FIXME remove "irq_disabled"
- unsigned irq_disabled:1; /* P: lock */
- unsigned disabled:1;
- unsigned is_suspended:1;
+ struct mutex lock;
+ bool stopped; /* P: lock */
+ bool disabled; /* P: lock */
+ bool suspended; /* P: lock */
int (*filter)(void *data, int data_idx, int *val);
void *filter_data;
@@ -165,7 +167,7 @@ struct ads7846 {
#define ADS_12_BIT (0 << 3)
#define ADS_SER (1 << 2) /* non-differential */
#define ADS_DFR (0 << 2) /* differential */
-#define ADS_PD10_PDOWN (0 << 0) /* lowpower mode + penirq */
+#define ADS_PD10_PDOWN (0 << 0) /* low power mode + penirq */
#define ADS_PD10_ADC_ON (1 << 0) /* ADC on */
#define ADS_PD10_REF_ON (2 << 0) /* vREF on + penirq */
#define ADS_PD10_ALL_ON (3 << 0) /* ADC + vREF on */
@@ -193,6 +195,78 @@ struct ads7846 {
#define REF_ON (READ_12BIT_DFR(x, 1, 1))
#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
+/* Must be called with ts->lock held */
+static void ads7846_stop(struct ads7846 *ts)
+{
+ if (!ts->disabled && !ts->suspended) {
+ /* Signal IRQ thread to stop polling and disable the handler. */
+ ts->stopped = true;
+ mb();
+ wake_up(&ts->wait);
+ disable_irq(ts->spi->irq);
+ }
+}
+
+/* Must be called with ts->lock held */
+static void ads7846_restart(struct ads7846 *ts)
+{
+ if (!ts->disabled && !ts->suspended) {
+ /* Tell IRQ thread that it may poll the device. */
+ ts->stopped = false;
+ mb();
+ enable_irq(ts->spi->irq);
+ }
+}
+
+/* Must be called with ts->lock held */
+static void __ads7846_disable(struct ads7846 *ts)
+{
+ ads7846_stop(ts);
+ regulator_disable(ts->reg);
+
+ /*
+ * We know the chip's in low power mode since we always
+ * leave it that way after every request
+ */
+}
+
+/* Must be called with ts->lock held */
+static void __ads7846_enable(struct ads7846 *ts)
+{
+ regulator_enable(ts->reg);
+ ads7846_restart(ts);
+}
+
+static void ads7846_disable(struct ads7846 *ts)
+{
+ mutex_lock(&ts->lock);
+
+ if (!ts->disabled) {
+
+ if (!ts->suspended)
+ __ads7846_disable(ts);
+
+ ts->disabled = true;
+ }
+
+ mutex_unlock(&ts->lock);
+}
+
+static void ads7846_enable(struct ads7846 *ts)
+{
+ mutex_lock(&ts->lock);
+
+ if (ts->disabled) {
+
+ ts->disabled = false;
+
+ if (!ts->suspended)
+ __ads7846_enable(ts);
+ }
+
+ mutex_unlock(&ts->lock);
+}
+
/*--------------------------------------------------------------------------*/
/*
@@ -219,23 +293,15 @@ struct ads7845_ser_req {
struct spi_transfer xfer[2];
};
-static void ads7846_enable(struct ads7846 *ts);
-static void ads7846_disable(struct ads7846 *ts);
-
-static int device_suspended(struct device *dev)
-{
- struct ads7846 *ts = dev_get_drvdata(dev);
- return ts->is_suspended || ts->disabled;
-}
-
static int ads7846_read12_ser(struct device *dev, unsigned command)
{
- struct spi_device *spi = to_spi_device(dev);
- struct ads7846 *ts = dev_get_drvdata(dev);
- struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
- int status;
- int use_internal;
+ struct spi_device *spi = to_spi_device(dev);
+ struct ads7846 *ts = dev_get_drvdata(dev);
+ struct ser_req *req;
+ int status;
+ int use_internal;
+ req = kzalloc(sizeof *req, GFP_KERNEL);
if (!req)
return -ENOMEM;
@@ -282,11 +348,11 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
CS_CHANGE(req->xfer[5]);
spi_message_add_tail(&req->xfer[5], &req->msg);
- ts->irq_disabled = 1;
- disable_irq(spi->irq);
+ mutex_lock(&ts->lock);
+ ads7846_stop(ts);
status = spi_sync(spi, &req->msg);
- ts->irq_disabled = 0;
- enable_irq(spi->irq);
+ ads7846_restart(ts);
+ mutex_unlock(&ts->lock);
if (status == 0) {
/* on-wire is a must-ignore bit, a BE12 value, then padding */
@@ -301,11 +367,12 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
static int ads7845_read12_ser(struct device *dev, unsigned command)
{
- struct spi_device *spi = to_spi_device(dev);
- struct ads7846 *ts = dev_get_drvdata(dev);
- struct ads7845_ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
- int status;
+ struct spi_device *spi = to_spi_device(dev);
+ struct ads7846 *ts = dev_get_drvdata(dev);
+ struct ads7845_ser_req *req;
+ int status;
+ req = kzalloc(sizeof *req, GFP_KERNEL);
if (!req)
return -ENOMEM;
@@ -317,11 +384,11 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)
req->xfer[0].len = 3;
spi_message_add_tail(&req->xfer[0], &req->msg);
- ts->irq_disabled = 1;
- disable_irq(spi->irq);
+ mutex_lock(&ts->lock);
+ ads7846_stop(ts);
status = spi_sync(spi, &req->msg);
- ts->irq_disabled = 0;
- enable_irq(spi->irq);
+ ads7846_restart(ts);
+ mutex_unlock(&ts->lock);
if (status == 0) {
/* BE12 value, then padding */
@@ -374,6 +441,7 @@ static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
/* external resistors may scale vAUX into 0..vREF */
retval *= ts->vref_mv;
retval = retval >> 12;
+
return retval;
}
@@ -384,13 +452,13 @@ static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
/* ads7846 has a resistor ladder to scale this signal down */
if (ts->model == 7846)
retval *= 4;
+
return retval;
}
SHOW(in0_input, vaux, vaux_adjust)
SHOW(in1_input, vbatt, vbatt_adjust)
-
static struct attribute *ads7846_attributes[] = {
&dev_attr_temp0.attr,
&dev_attr_temp1.attr,
@@ -498,17 +566,12 @@ static inline void ads784x_hwmon_unregister(struct spi_device *spi,
}
#endif
-static int is_pen_down(struct device *dev)
-{
- struct ads7846 *ts = dev_get_drvdata(dev);
-
- return ts->pendown;
-}
-
static ssize_t ads7846_pen_down_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%u\n", is_pen_down(dev));
+ struct ads7846 *ts = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", ts->pendown);
}
static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);
@@ -516,7 +579,7 @@ static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);
static ssize_t ads7846_disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ads7846 *ts = dev_get_drvdata(dev);
+ struct ads7846 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->disabled);
}
@@ -531,15 +594,11 @@ static ssize_t ads7846_disable_store(struct device *dev,
if (strict_strtoul(buf, 10, &i))
return -EINVAL;
- spin_lock_irq(&ts->lock);
-
if (i)
ads7846_disable(ts);
else
ads7846_enable(ts);
- spin_unlock_irq(&ts->lock);
-
return count;
}
@@ -569,23 +628,141 @@ static void null_wait_for_sync(void)
{
}
-/*
- * PENIRQ only kicks the timer. The timer only reissues the SPI transfer,
- * to retrieve touchscreen status.
- *
- * The SPI transfer completion callback does the real work. It reports
- * touchscreen events and reactivates the timer (or IRQ) as appropriate.
- */
+static int ads7846_debounce_filter(void *ads, int data_idx, int *val)
+{
+ struct ads7846 *ts = ads;
+
+ if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
+ /* Start over collecting consistent readings. */
+ ts->read_rep = 0;
+ /*
+ * Repeat it, if this was the first read or the read
+ * wasn't consistent enough.
+ */
+ if (ts->read_cnt < ts->debounce_max) {
+ ts->last_read = *val;
+ ts->read_cnt++;
+ return ADS7846_FILTER_REPEAT;
+ } else {
+ /*
+ * Maximum number of debouncing reached and still
+ * not enough number of consistent readings. Abort
+ * the whole sample, repeat it in the next sampling
+ * period.
+ */
+ ts->read_cnt = 0;
+ return ADS7846_FILTER_IGNORE;
+ }
+ } else {
+ if (++ts->read_rep > ts->debounce_rep) {
+ /*
+ * Got a good reading for this coordinate,
+ * go for the next one.
+ */
+ ts->read_cnt = 0;
+ ts->read_rep = 0;
+ return ADS7846_FILTER_OK;
+ } else {
+ /* Read more values that are consistent. */
+ ts->read_cnt++;
+ return ADS7846_FILTER_REPEAT;
+ }
+ }
+}
+
+static int ads7846_no_filter(void *ads, int data_idx, int *val)
+{
+ return ADS7846_FILTER_OK;
+}
+
+static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
+{
+ struct spi_transfer *t =
+ list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+
+ if (ts->model == 7845) {
+ return be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
+ } else {
+ /*
+ * adjust: on-wire is a must-ignore bit, a BE12 value, then
+ * padding; built from two 8 bit values written msb-first.
+ */
+ return be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+ }
+}
+
+static void ads7846_update_value(struct spi_message *m, int val)
+{
+ struct spi_transfer *t =
+ list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+
+ *(u16 *)t->rx_buf = val;
+}
+
+static void ads7846_read_state(struct ads7846 *ts)
+{
+ struct ads7846_packet *packet = ts->packet;
+ struct spi_message *m;
+ int msg_idx = 0;
+ int val;
+ int action;
+ int error;
+
+ while (msg_idx < ts->msg_count) {
+
+ ts->wait_for_sync();
+
+ m = &ts->msg[msg_idx];
+ error = spi_sync(ts->spi, m);
+ if (error) {
+ dev_err(&ts->spi->dev, "spi_async --> %d\n", error);
+ packet->tc.ignore = true;
+ return;
+ }
+
+ /*
+ * Last message is power down request, no need to convert
+ * or filter the value.
+ */
+ if (msg_idx < ts->msg_count - 1) {
-static void ads7846_rx(void *ads)
+ val = ads7846_get_value(ts, m);
+
+ action = ts->filter(ts->filter_data, msg_idx, &val);
+ switch (action) {
+ case ADS7846_FILTER_REPEAT:
+ continue;
+
+ case ADS7846_FILTER_IGNORE:
+ packet->tc.ignore = true;
+ msg_idx = ts->msg_count - 1;
+ continue;
+
+ case ADS7846_FILTER_OK:
+ ads7846_update_value(m, val);
+ packet->tc.ignore = false;
+ msg_idx++;
+ break;
+
+ default:
+ BUG();
+ }
+ } else {
+ msg_idx++;
+ }
+ }
+}
+
+static void ads7846_report_state(struct ads7846 *ts)
{
- struct ads7846 *ts = ads;
- struct ads7846_packet *packet = ts->packet;
- unsigned Rt;
- u16 x, y, z1, z2;
+ struct ads7846_packet *packet = ts->packet;
+ unsigned int Rt;
+ u16 x, y, z1, z2;
- /* ads7846_rx_val() did in-place conversion (including byteswap) from
- * on-the-wire format as part of debouncing to get stable readings.
+ /*
+ * ads7846_get_value() does in-place conversion (including byte swap)
+ * from on-the-wire format as part of debouncing to get stable
+ * readings.
*/
if (ts->model == 7845) {
x = *(u16 *)packet->tc.x_buf;
@@ -623,19 +800,19 @@ static void ads7846_rx(void *ads)
Rt = 0;
}
- /* Sample found inconsistent by debouncing or pressure is beyond
+ /*
+ * Sample found inconsistent by debouncing or pressure is beyond
* the maximum. Don't report it to user space, repeat at least
* once more the measurement
*/
if (packet->tc.ignore || Rt > ts->pressure_max) {
dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
packet->tc.ignore, Rt);
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_MODE_REL);
return;
}
- /* Maybe check the pendown state before reporting. This discards
+ /*
+ * Maybe check the pendown state before reporting. This discards
* false readings when the pen is lifted.
*/
if (ts->penirq_recheck_delay_usecs) {
@@ -644,8 +821,9 @@ static void ads7846_rx(void *ads)
Rt = 0;
}
- /* NOTE: We can't rely on the pressure to determine the pen down
- * state, even this controller has a pressure sensor. The pressure
+ /*
+ * NOTE: We can't rely on the pressure to determine the pen down
+ * state, even this controller has a pressure sensor. The pressure
* value can fluctuate for quite a while after lifting the pen and
* in some cases may not even settle at the expected value.
*
@@ -655,15 +833,15 @@ static void ads7846_rx(void *ads)
if (Rt) {
struct input_dev *input = ts->input;
+ if (ts->swap_xy)
+ swap(x, y);
+
if (!ts->pendown) {
input_report_key(input, BTN_TOUCH, 1);
- ts->pendown = 1;
+ ts->pendown = true;
dev_vdbg(&ts->spi->dev, "DOWN\n");
}
- if (ts->swap_xy)
- swap(x, y);
-
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt);
@@ -671,246 +849,94 @@ static void ads7846_rx(void *ads)
input_sync(input);
dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
}
-
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_MODE_REL);
-}
-
-static int ads7846_debounce(void *ads, int data_idx, int *val)
-{
- struct ads7846 *ts = ads;
-
- if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
- /* Start over collecting consistent readings. */
- ts->read_rep = 0;
- /* Repeat it, if this was the first read or the read
- * wasn't consistent enough. */
- if (ts->read_cnt < ts->debounce_max) {
- ts->last_read = *val;
- ts->read_cnt++;
- return ADS7846_FILTER_REPEAT;
- } else {
- /* Maximum number of debouncing reached and still
- * not enough number of consistent readings. Abort
- * the whole sample, repeat it in the next sampling
- * period.
- */
- ts->read_cnt = 0;
- return ADS7846_FILTER_IGNORE;
- }
- } else {
- if (++ts->read_rep > ts->debounce_rep) {
- /* Got a good reading for this coordinate,
- * go for the next one. */
- ts->read_cnt = 0;
- ts->read_rep = 0;
- return ADS7846_FILTER_OK;
- } else {
- /* Read more values that are consistent. */
- ts->read_cnt++;
- return ADS7846_FILTER_REPEAT;
- }
- }
}
-static int ads7846_no_filter(void *ads, int data_idx, int *val)
+static irqreturn_t ads7846_hard_irq(int irq, void *handle)
{
- return ADS7846_FILTER_OK;
-}
-
-static void ads7846_rx_val(void *ads)
-{
- struct ads7846 *ts = ads;
- struct ads7846_packet *packet = ts->packet;
- struct spi_message *m;
- struct spi_transfer *t;
- int val;
- int action;
- int status;
-
- m = &ts->msg[ts->msg_idx];
- t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
-
- if (ts->model == 7845) {
- val = be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
- } else {
- /* adjust: on-wire is a must-ignore bit, a BE12 value, then
- * padding; built from two 8 bit values written msb-first.
- */
- val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
- }
+ struct ads7846 *ts = handle;
- action = ts->filter(ts->filter_data, ts->msg_idx, &val);
- switch (action) {
- case ADS7846_FILTER_REPEAT:
- break;
- case ADS7846_FILTER_IGNORE:
- packet->tc.ignore = 1;
- /* Last message will contain ads7846_rx() as the
- * completion function.
- */
- m = ts->last_msg;
- break;
- case ADS7846_FILTER_OK:
- *(u16 *)t->rx_buf = val;
- packet->tc.ignore = 0;
- m = &ts->msg[++ts->msg_idx];
- break;
- default:
- BUG();
- }
- ts->wait_for_sync();
- status = spi_async(ts->spi, m);
- if (status)
- dev_err(&ts->spi->dev, "spi_async --> %d\n",
- status);
+ return get_pendown_state(ts) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
}
-static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
-{
- struct ads7846 *ts = container_of(handle, struct ads7846, timer);
- int status = 0;
-
- spin_lock(&ts->lock);
-
- if (unlikely(!get_pendown_state(ts) ||
- device_suspended(&ts->spi->dev))) {
- if (ts->pendown) {
- struct input_dev *input = ts->input;
-
- input_report_key(input, BTN_TOUCH, 0);
- input_report_abs(input, ABS_PRESSURE, 0);
- input_sync(input);
-
- ts->pendown = 0;
- dev_vdbg(&ts->spi->dev, "UP\n");
- }
-
- /* measurement cycle ended */
- if (!device_suspended(&ts->spi->dev)) {
- ts->irq_disabled = 0;
- enable_irq(ts->spi->irq);
- }
- ts->pending = 0;
- } else {
- /* pen is still down, continue with the measurement */
- ts->msg_idx = 0;
- ts->wait_for_sync();
- status = spi_async(ts->spi, &ts->msg[0]);
- if (status)
- dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
- }
-
- spin_unlock(&ts->lock);
- return HRTIMER_NORESTART;
-}
static irqreturn_t ads7846_irq(int irq, void *handle)
{
struct ads7846 *ts = handle;
- unsigned long flags;
-
- spin_lock_irqsave(&ts->lock, flags);
- if (likely(get_pendown_state(ts))) {
- if (!ts->irq_disabled) {
- /* The ARM do_simple_IRQ() dispatcher doesn't act
- * like the other dispatchers: it will report IRQs
- * even after they've been disabled. We work around
- * that here. (The "generic irq" framework may help...)
- */
- ts->irq_disabled = 1;
- disable_irq_nosync(ts->spi->irq);
- ts->pending = 1;
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
- HRTIMER_MODE_REL);
- }
- }
- spin_unlock_irqrestore(&ts->lock, flags);
- return IRQ_HANDLED;
-}
+ /* Start with a small delay before checking pendown state */
+ msleep(TS_POLL_DELAY);
-/*--------------------------------------------------------------------------*/
+ while (!ts->stopped && get_pendown_state(ts)) {
-/* Must be called with ts->lock held */
-static void ads7846_disable(struct ads7846 *ts)
-{
- if (ts->disabled)
- return;
+ /* pen is down, continue with the measurement */
+ ads7846_read_state(ts);
- ts->disabled = 1;
+ if (!ts->stopped)
+ ads7846_report_state(ts);
- /* are we waiting for IRQ, or polling? */
- if (!ts->pending) {
- ts->irq_disabled = 1;
- disable_irq(ts->spi->irq);
- } else {
- /* the timer will run at least once more, and
- * leave everything in a clean state, IRQ disabled
- */
- while (ts->pending) {
- spin_unlock_irq(&ts->lock);
- msleep(1);
- spin_lock_irq(&ts->lock);
- }
+ wait_event_timeout(ts->wait, ts->stopped,
+ msecs_to_jiffies(TS_POLL_PERIOD));
}
- regulator_disable(ts->reg);
-
- /* we know the chip's in lowpower mode since we always
- * leave it that way after every request
- */
-}
+ if (ts->pendown) {
+ struct input_dev *input = ts->input;
-/* Must be called with ts->lock held */
-static void ads7846_enable(struct ads7846 *ts)
-{
- if (!ts->disabled)
- return;
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ input_sync(input);
- regulator_enable(ts->reg);
+ ts->pendown = false;
+ dev_vdbg(&ts->spi->dev, "UP\n");
+ }
- ts->disabled = 0;
- ts->irq_disabled = 0;
- enable_irq(ts->spi->irq);
+ return IRQ_HANDLED;
}
static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
- spin_lock_irq(&ts->lock);
+ mutex_lock(&ts->lock);
- ts->is_suspended = 1;
- ads7846_disable(ts);
+ if (!ts->suspended) {
- spin_unlock_irq(&ts->lock);
+ if (!ts->disabled)
+ __ads7846_disable(ts);
- if (device_may_wakeup(&ts->spi->dev))
- enable_irq_wake(ts->spi->irq);
+ if (device_may_wakeup(&ts->spi->dev))
+ enable_irq_wake(ts->spi->irq);
- return 0;
+ ts->suspended = true;
+ }
+
+ mutex_unlock(&ts->lock);
+ return 0;
}
static int ads7846_resume(struct spi_device *spi)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
- if (device_may_wakeup(&ts->spi->dev))
- disable_irq_wake(ts->spi->irq);
+ mutex_lock(&ts->lock);
+
+ if (ts->suspended) {
- spin_lock_irq(&ts->lock);
+ ts->suspended = false;
- ts->is_suspended = 0;
- ads7846_enable(ts);
+ if (device_may_wakeup(&ts->spi->dev))
+ disable_irq_wake(ts->spi->irq);
- spin_unlock_irq(&ts->lock);
+ if (!ts->disabled)
+ __ads7846_enable(ts);
+ }
+
+ mutex_unlock(&ts->lock);
return 0;
}
-static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
+static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts)
{
struct ads7846_platform_data *pdata = spi->dev.platform_data;
int err;
@@ -932,146 +958,40 @@ static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
if (err) {
dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
- pdata->gpio_pendown);
+ pdata->gpio_pendown);
return err;
}
ts->gpio_pendown = pdata->gpio_pendown;
+
return 0;
}
-static int __devinit ads7846_probe(struct spi_device *spi)
+/*
+ * Set up the transfers to read touchscreen state; this assumes we
+ * use formula #2 for pressure, not #3.
+ */
+static void __devinit ads7846_setup_spi_msg(struct ads7846 *ts,
+ const struct ads7846_platform_data *pdata)
{
- struct ads7846 *ts;
- struct ads7846_packet *packet;
- struct input_dev *input_dev;
- const struct ads7846_platform_data *pdata = spi->dev.platform_data;
- struct spi_message *m;
- struct spi_transfer *x;
- unsigned long irq_flags;
- int vref;
- int err;
-
- if (!spi->irq) {
- dev_dbg(&spi->dev, "no IRQ?\n");
- return -ENODEV;
- }
-
- if (!pdata) {
- dev_dbg(&spi->dev, "no platform data?\n");
- return -ENODEV;
- }
-
- /* don't exceed max specified sample rate */
- if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
- dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
- (spi->max_speed_hz/SAMPLE_BITS)/1000);
- return -EINVAL;
- }
-
- /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
- * that even if the hardware can do that, the SPI controller driver
- * may not. So we stick to very-portable 8 bit words, both RX and TX.
- */
- spi->bits_per_word = 8;
- spi->mode = SPI_MODE_0;
- err = spi_setup(spi);
- if (err < 0)
- return err;
-
- ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
- packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ts || !packet || !input_dev) {
- err = -ENOMEM;
- goto err_free_mem;
- }
-
- dev_set_drvdata(&spi->dev, ts);
-
- ts->packet = packet;
- ts->spi = spi;
- ts->input = input_dev;
- ts->vref_mv = pdata->vref_mv;
- ts->swap_xy = pdata->swap_xy;
-
- hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- ts->timer.function = ads7846_timer;
-
- spin_lock_init(&ts->lock);
-
- ts->model = pdata->model ? : 7846;
- ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
- ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
- ts->pressure_max = pdata->pressure_max ? : ~0;
-
- if (pdata->filter != NULL) {
- if (pdata->filter_init != NULL) {
- err = pdata->filter_init(pdata, &ts->filter_data);
- if (err < 0)
- goto err_free_mem;
- }
- ts->filter = pdata->filter;
- ts->filter_cleanup = pdata->filter_cleanup;
- } else if (pdata->debounce_max) {
- ts->debounce_max = pdata->debounce_max;
- if (ts->debounce_max < 2)
- ts->debounce_max = 2;
- ts->debounce_tol = pdata->debounce_tol;
- ts->debounce_rep = pdata->debounce_rep;
- ts->filter = ads7846_debounce;
- ts->filter_data = ts;
- } else
- ts->filter = ads7846_no_filter;
-
- err = setup_pendown(spi, ts);
- if (err)
- goto err_cleanup_filter;
-
- if (pdata->penirq_recheck_delay_usecs)
- ts->penirq_recheck_delay_usecs =
- pdata->penirq_recheck_delay_usecs;
-
- ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
-
- snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
- snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
-
- input_dev->name = ts->name;
- input_dev->phys = ts->phys;
- input_dev->dev.parent = &spi->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X,
- pdata->x_min ? : 0,
- pdata->x_max ? : MAX_12BIT,
- 0, 0);
- input_set_abs_params(input_dev, ABS_Y,
- pdata->y_min ? : 0,
- pdata->y_max ? : MAX_12BIT,
- 0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE,
- pdata->pressure_min, pdata->pressure_max, 0, 0);
-
- vref = pdata->keep_vref_on;
+ struct spi_message *m = &ts->msg[0];
+ struct spi_transfer *x = ts->xfer;
+ struct ads7846_packet *packet = ts->packet;
+ int vref = pdata->keep_vref_on;
if (ts->model == 7873) {
- /* The AD7873 is almost identical to the ADS7846
+ /*
+ * The AD7873 is almost identical to the ADS7846
* keep VREF off during differential/ratiometric
- * conversion modes
+ * conversion modes.
*/
ts->model = 7846;
vref = 0;
}
- /* set up the transfers to read touchscreen state; this assumes we
- * use formula #2 for pressure, not #3.
- */
- m = &ts->msg[0];
- x = ts->xfer;
-
+ ts->msg_count = 1;
spi_message_init(m);
+ m->context = ts;
if (ts->model == 7845) {
packet->read_y_cmd[0] = READ_Y(vref);
@@ -1094,7 +1014,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_add_tail(x, m);
}
- /* the first sample after switching drivers can be low quality;
+ /*
+ * The first sample after switching drivers can be low quality;
* optionally discard it, using a second one after the signals
* have had enough time to stabilize.
*/
@@ -1112,11 +1033,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_add_tail(x, m);
}
- m->complete = ads7846_rx_val;
- m->context = ts;
-
+ ts->msg_count++;
m++;
spi_message_init(m);
+ m->context = ts;
if (ts->model == 7845) {
x++;
@@ -1156,13 +1076,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_add_tail(x, m);
}
- m->complete = ads7846_rx_val;
- m->context = ts;
-
/* turn y+ off, x- on; we'll use formula #2 */
if (ts->model == 7846) {
+ ts->msg_count++;
m++;
spi_message_init(m);
+ m->context = ts;
x++;
packet->read_z1 = READ_Z1(vref);
@@ -1190,11 +1109,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_add_tail(x, m);
}
- m->complete = ads7846_rx_val;
- m->context = ts;
-
+ ts->msg_count++;
m++;
spi_message_init(m);
+ m->context = ts;
x++;
packet->read_z2 = READ_Z2(vref);
@@ -1221,14 +1139,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
}
-
- m->complete = ads7846_rx_val;
- m->context = ts;
}
/* power down */
+ ts->msg_count++;
m++;
spi_message_init(m);
+ m->context = ts;
if (ts->model == 7845) {
x++;
@@ -1251,11 +1168,119 @@ static int __devinit ads7846_probe(struct spi_device *spi)
CS_CHANGE(*x);
spi_message_add_tail(x, m);
+}
- m->complete = ads7846_rx;
- m->context = ts;
+static int __devinit ads7846_probe(struct spi_device *spi)
+{
+ struct ads7846 *ts;
+ struct ads7846_packet *packet;
+ struct input_dev *input_dev;
+ struct ads7846_platform_data *pdata = spi->dev.platform_data;
+ unsigned long irq_flags;
+ int err;
+
+ if (!spi->irq) {
+ dev_dbg(&spi->dev, "no IRQ?\n");
+ return -ENODEV;
+ }
+
+ if (!pdata) {
+ dev_dbg(&spi->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ /* don't exceed max specified sample rate */
+ if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
+ dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
+ (spi->max_speed_hz/SAMPLE_BITS)/1000);
+ return -EINVAL;
+ }
+
+ /* We'd set TX word size 8 bits and RX word size to 13 bits ... except
+ * that even if the hardware can do that, the SPI controller driver
+ * may not. So we stick to very-portable 8 bit words, both RX and TX.
+ */
+ spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_0;
+ err = spi_setup(spi);
+ if (err < 0)
+ return err;
- ts->last_msg = m;
+ ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
+ packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ts || !packet || !input_dev) {
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ dev_set_drvdata(&spi->dev, ts);
+
+ ts->packet = packet;
+ ts->spi = spi;
+ ts->input = input_dev;
+ ts->vref_mv = pdata->vref_mv;
+ ts->swap_xy = pdata->swap_xy;
+
+ mutex_init(&ts->lock);
+ init_waitqueue_head(&ts->wait);
+
+ ts->model = pdata->model ? : 7846;
+ ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
+ ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+ ts->pressure_max = pdata->pressure_max ? : ~0;
+
+ if (pdata->filter != NULL) {
+ if (pdata->filter_init != NULL) {
+ err = pdata->filter_init(pdata, &ts->filter_data);
+ if (err < 0)
+ goto err_free_mem;
+ }
+ ts->filter = pdata->filter;
+ ts->filter_cleanup = pdata->filter_cleanup;
+ } else if (pdata->debounce_max) {
+ ts->debounce_max = pdata->debounce_max;
+ if (ts->debounce_max < 2)
+ ts->debounce_max = 2;
+ ts->debounce_tol = pdata->debounce_tol;
+ ts->debounce_rep = pdata->debounce_rep;
+ ts->filter = ads7846_debounce_filter;
+ ts->filter_data = ts;
+ } else {
+ ts->filter = ads7846_no_filter;
+ }
+
+ err = ads7846_setup_pendown(spi, ts);
+ if (err)
+ goto err_cleanup_filter;
+
+ if (pdata->penirq_recheck_delay_usecs)
+ ts->penirq_recheck_delay_usecs =
+ pdata->penirq_recheck_delay_usecs;
+
+ ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
+
+ snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
+ snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
+
+ input_dev->name = ts->name;
+ input_dev->phys = ts->phys;
+ input_dev->dev.parent = &spi->dev;
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_abs_params(input_dev, ABS_X,
+ pdata->x_min ? : 0,
+ pdata->x_max ? : MAX_12BIT,
+ 0, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ pdata->y_min ? : 0,
+ pdata->y_max ? : MAX_12BIT,
+ 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ pdata->pressure_min, pdata->pressure_max, 0, 0);
+
+ ads7846_setup_spi_msg(ts, pdata);
ts->reg = regulator_get(&spi->dev, "vcc");
if (IS_ERR(ts->reg)) {
@@ -1271,16 +1296,17 @@ static int __devinit ads7846_probe(struct spi_device *spi)
}
irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
+ irq_flags |= IRQF_ONESHOT;
- err = request_irq(spi->irq, ads7846_irq, irq_flags,
- spi->dev.driver->name, ts);
-
+ err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq,
+ irq_flags, spi->dev.driver->name, ts);
if (err && !pdata->irq_flags) {
dev_info(&spi->dev,
"trying pin change workaround on irq %d\n", spi->irq);
- err = request_irq(spi->irq, ads7846_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- spi->dev.driver->name, ts);
+ irq_flags |= IRQF_TRIGGER_RISING;
+ err = request_threaded_irq(spi->irq,
+ ads7846_hard_irq, ads7846_irq,
+ irq_flags, spi->dev.driver->name, ts);
}
if (err) {
@@ -1294,7 +1320,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
- /* take a first sample, leaving nPENIRQ active and vREF off; avoid
+ /*
+ * Take a first sample, leaving nPENIRQ active and vREF off; avoid
* the touchscreen, in case it's not connected.
*/
if (ts->model == 7845)
@@ -1340,20 +1367,18 @@ static int __devinit ads7846_probe(struct spi_device *spi)
static int __devexit ads7846_remove(struct spi_device *spi)
{
- struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+ struct ads7846 *ts = dev_get_drvdata(&spi->dev);
device_init_wakeup(&spi->dev, false);
- ads784x_hwmon_unregister(spi, ts);
- input_unregister_device(ts->input);
-
- ads7846_suspend(spi, PMSG_SUSPEND);
-
sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
+ ads7846_disable(ts);
free_irq(ts->spi->irq, ts);
- /* suspend left the IRQ disabled */
- enable_irq(ts->spi->irq);
+
+ input_unregister_device(ts->input);
+
+ ads784x_hwmon_unregister(spi, ts);
regulator_disable(ts->reg);
regulator_put(ts->reg);
@@ -1368,6 +1393,7 @@ static int __devexit ads7846_remove(struct spi_device *spi)
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
+
return 0;
}
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
new file mode 100644
index 000000000000..ccde58602563
--- /dev/null
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * License terms:GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+#include <linux/input/bu21013.h>
+#include <linux/slab.h>
+
+#define PEN_DOWN_INTR 0
+#define MAX_FINGERS 2
+#define RESET_DELAY 30
+#define PENUP_TIMEOUT (10)
+#define DELTA_MIN 16
+#define MASK_BITS 0x03
+#define SHIFT_8 8
+#define SHIFT_2 2
+#define LENGTH_OF_BUFFER 11
+#define I2C_RETRY_COUNT 5
+
+#define BU21013_SENSORS_BTN_0_7_REG 0x70
+#define BU21013_SENSORS_BTN_8_15_REG 0x71
+#define BU21013_SENSORS_BTN_16_23_REG 0x72
+#define BU21013_X1_POS_MSB_REG 0x73
+#define BU21013_X1_POS_LSB_REG 0x74
+#define BU21013_Y1_POS_MSB_REG 0x75
+#define BU21013_Y1_POS_LSB_REG 0x76
+#define BU21013_X2_POS_MSB_REG 0x77
+#define BU21013_X2_POS_LSB_REG 0x78
+#define BU21013_Y2_POS_MSB_REG 0x79
+#define BU21013_Y2_POS_LSB_REG 0x7A
+#define BU21013_INT_CLR_REG 0xE8
+#define BU21013_INT_MODE_REG 0xE9
+#define BU21013_GAIN_REG 0xEA
+#define BU21013_OFFSET_MODE_REG 0xEB
+#define BU21013_XY_EDGE_REG 0xEC
+#define BU21013_RESET_REG 0xED
+#define BU21013_CALIB_REG 0xEE
+#define BU21013_DONE_REG 0xEF
+#define BU21013_SENSOR_0_7_REG 0xF0
+#define BU21013_SENSOR_8_15_REG 0xF1
+#define BU21013_SENSOR_16_23_REG 0xF2
+#define BU21013_POS_MODE1_REG 0xF3
+#define BU21013_POS_MODE2_REG 0xF4
+#define BU21013_CLK_MODE_REG 0xF5
+#define BU21013_IDLE_REG 0xFA
+#define BU21013_FILTER_REG 0xFB
+#define BU21013_TH_ON_REG 0xFC
+#define BU21013_TH_OFF_REG 0xFD
+
+
+#define BU21013_RESET_ENABLE 0x01
+
+#define BU21013_SENSORS_EN_0_7 0x3F
+#define BU21013_SENSORS_EN_8_15 0xFC
+#define BU21013_SENSORS_EN_16_23 0x1F
+
+#define BU21013_POS_MODE1_0 0x02
+#define BU21013_POS_MODE1_1 0x04
+#define BU21013_POS_MODE1_2 0x08
+
+#define BU21013_POS_MODE2_ZERO 0x01
+#define BU21013_POS_MODE2_AVG1 0x02
+#define BU21013_POS_MODE2_AVG2 0x04
+#define BU21013_POS_MODE2_EN_XY 0x08
+#define BU21013_POS_MODE2_EN_RAW 0x10
+#define BU21013_POS_MODE2_MULTI 0x80
+
+#define BU21013_CLK_MODE_DIV 0x01
+#define BU21013_CLK_MODE_EXT 0x02
+#define BU21013_CLK_MODE_CALIB 0x80
+
+#define BU21013_IDLET_0 0x01
+#define BU21013_IDLET_1 0x02
+#define BU21013_IDLET_2 0x04
+#define BU21013_IDLET_3 0x08
+#define BU21013_IDLE_INTERMIT_EN 0x10
+
+#define BU21013_DELTA_0_6 0x7F
+#define BU21013_FILTER_EN 0x80
+
+#define BU21013_INT_MODE_LEVEL 0x00
+#define BU21013_INT_MODE_EDGE 0x01
+
+#define BU21013_GAIN_0 0x01
+#define BU21013_GAIN_1 0x02
+#define BU21013_GAIN_2 0x04
+
+#define BU21013_OFFSET_MODE_DEFAULT 0x00
+#define BU21013_OFFSET_MODE_MOVE 0x01
+#define BU21013_OFFSET_MODE_DISABLE 0x02
+
+#define BU21013_TH_ON_0 0x01
+#define BU21013_TH_ON_1 0x02
+#define BU21013_TH_ON_2 0x04
+#define BU21013_TH_ON_3 0x08
+#define BU21013_TH_ON_4 0x10
+#define BU21013_TH_ON_5 0x20
+#define BU21013_TH_ON_6 0x40
+#define BU21013_TH_ON_7 0x80
+#define BU21013_TH_ON_MAX 0xFF
+
+#define BU21013_TH_OFF_0 0x01
+#define BU21013_TH_OFF_1 0x02
+#define BU21013_TH_OFF_2 0x04
+#define BU21013_TH_OFF_3 0x08
+#define BU21013_TH_OFF_4 0x10
+#define BU21013_TH_OFF_5 0x20
+#define BU21013_TH_OFF_6 0x40
+#define BU21013_TH_OFF_7 0x80
+#define BU21013_TH_OFF_MAX 0xFF
+
+#define BU21013_X_EDGE_0 0x01
+#define BU21013_X_EDGE_1 0x02
+#define BU21013_X_EDGE_2 0x04
+#define BU21013_X_EDGE_3 0x08
+#define BU21013_Y_EDGE_0 0x10
+#define BU21013_Y_EDGE_1 0x20
+#define BU21013_Y_EDGE_2 0x40
+#define BU21013_Y_EDGE_3 0x80
+
+#define BU21013_DONE 0x01
+#define BU21013_NUMBER_OF_X_SENSORS (6)
+#define BU21013_NUMBER_OF_Y_SENSORS (11)
+
+#define DRIVER_TP "bu21013_tp"
+
+/**
+ * struct bu21013_ts_data - touch panel data structure
+ * @client: pointer to the i2c client
+ * @wait: variable to wait_queue_head_t structure
+ * @touch_stopped: touch stop flag
+ * @chip: pointer to the touch panel controller
+ * @in_dev: pointer to the input device structure
+ * @intr_pin: interrupt pin value
+ *
+ * Touch panel device data structure
+ */
+struct bu21013_ts_data {
+ struct i2c_client *client;
+ wait_queue_head_t wait;
+ bool touch_stopped;
+ const struct bu21013_platform_device *chip;
+ struct input_dev *in_dev;
+ unsigned int intr_pin;
+};
+
+/**
+ * bu21013_read_block_data(): read the touch co-ordinates
+ * @data: bu21013_ts_data structure pointer
+ * @buf: byte pointer
+ *
+ * Read the touch co-ordinates using i2c read block into buffer
+ * and returns integer.
+ */
+static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf)
+{
+ int ret, i;
+
+ for (i = 0; i < I2C_RETRY_COUNT; i++) {
+ ret = i2c_smbus_read_i2c_block_data
+ (data->client, BU21013_SENSORS_BTN_0_7_REG,
+ LENGTH_OF_BUFFER, buf);
+ if (ret == LENGTH_OF_BUFFER)
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/**
+ * bu21013_do_touch_report(): Get the touch co-ordinates
+ * @data: bu21013_ts_data structure pointer
+ *
+ * Get the touch co-ordinates from touch sensor registers and writes
+ * into device structure and returns integer.
+ */
+static int bu21013_do_touch_report(struct bu21013_ts_data *data)
+{
+ u8 buf[LENGTH_OF_BUFFER];
+ unsigned int pos_x[2], pos_y[2];
+ bool has_x_sensors, has_y_sensors;
+ int finger_down_count = 0;
+ int i;
+
+ if (data == NULL)
+ return -EINVAL;
+
+ if (bu21013_read_block_data(data, buf) < 0)
+ return -EINVAL;
+
+ has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7);
+ has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) |
+ ((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2);
+ if (!has_x_sensors || !has_y_sensors)
+ return 0;
+
+ for (i = 0; i < MAX_FINGERS; i++) {
+ const u8 *p = &buf[4 * i + 3];
+ unsigned int x = p[0] << SHIFT_2 | (p[1] & MASK_BITS);
+ unsigned int y = p[2] << SHIFT_2 | (p[3] & MASK_BITS);
+ if (x == 0 || y == 0)
+ continue;
+ pos_x[finger_down_count] = x;
+ pos_y[finger_down_count] = y;
+ finger_down_count++;
+ }
+
+ if (finger_down_count) {
+ if (finger_down_count == 2 &&
+ (abs(pos_x[0] - pos_x[1]) < DELTA_MIN ||
+ abs(pos_y[0] - pos_y[1]) < DELTA_MIN)) {
+ return 0;
+ }
+
+ for (i = 0; i < finger_down_count; i++) {
+ if (data->chip->x_flip)
+ pos_x[i] = data->chip->touch_x_max - pos_x[i];
+ if (data->chip->y_flip)
+ pos_y[i] = data->chip->touch_y_max - pos_y[i];
+
+ input_report_abs(data->in_dev,
+ ABS_MT_POSITION_X, pos_x[i]);
+ input_report_abs(data->in_dev,
+ ABS_MT_POSITION_Y, pos_y[i]);
+ input_mt_sync(data->in_dev);
+ }
+ } else
+ input_mt_sync(data->in_dev);
+
+ input_sync(data->in_dev);
+
+ return 0;
+}
+/**
+ * bu21013_gpio_irq() - gpio thread function for touch interrupt
+ * @irq: irq value
+ * @device_data: void pointer
+ *
+ * This gpio thread function for touch interrupt
+ * and returns irqreturn_t.
+ */
+static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
+{
+ struct bu21013_ts_data *data = device_data;
+ struct i2c_client *i2c = data->client;
+ int retval;
+
+ do {
+ retval = bu21013_do_touch_report(data);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "bu21013_do_touch_report failed\n");
+ return IRQ_NONE;
+ }
+
+ data->intr_pin = data->chip->irq_read_val();
+ if (data->intr_pin == PEN_DOWN_INTR)
+ wait_event_timeout(data->wait, data->touch_stopped,
+ msecs_to_jiffies(2));
+ } while (!data->intr_pin && !data->touch_stopped);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * bu21013_init_chip() - power on sequence for the bu21013 controller
+ * @data: device structure pointer
+ *
+ * This function is used to power on
+ * the bu21013 controller and returns integer.
+ */
+static int bu21013_init_chip(struct bu21013_ts_data *data)
+{
+ int retval;
+ struct i2c_client *i2c = data->client;
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET_REG,
+ BU21013_RESET_ENABLE);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_RESET reg write failed\n");
+ return retval;
+ }
+ msleep(RESET_DELAY);
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG,
+ BU21013_SENSORS_EN_0_7);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG,
+ BU21013_SENSORS_EN_8_15);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG,
+ BU21013_SENSORS_EN_16_23);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG,
+ (BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG,
+ (BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 |
+ BU21013_POS_MODE2_AVG2 | BU21013_POS_MODE2_EN_RAW |
+ BU21013_POS_MODE2_MULTI));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_POS_MODE2 reg write failed\n");
+ return retval;
+ }
+
+ if (data->chip->ext_clk)
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
+ (BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB));
+ else
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
+ (BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG,
+ (BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG,
+ BU21013_INT_MODE_LEVEL);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG,
+ (BU21013_DELTA_0_6 |
+ BU21013_FILTER_EN));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG,
+ BU21013_TH_ON_5);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
+ BU21013_TH_OFF_4 || BU21013_TH_OFF_3);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG,
+ (BU21013_GAIN_0 | BU21013_GAIN_1));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG,
+ BU21013_OFFSET_MODE_DEFAULT);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG,
+ (BU21013_X_EDGE_0 | BU21013_X_EDGE_2 |
+ BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG,
+ BU21013_DONE);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n");
+ return retval;
+ }
+
+ return 0;
+}
+
+/**
+ * bu21013_free_irq() - frees IRQ registered for touchscreen
+ * @bu21013_data: device structure pointer
+ *
+ * This function signals interrupt thread to stop processing and
+ * frees interrupt.
+ */
+static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data)
+{
+ bu21013_data->touch_stopped = true;
+ wake_up(&bu21013_data->wait);
+ free_irq(bu21013_data->chip->irq, bu21013_data);
+}
+
+/**
+ * bu21013_probe() - initializes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ * @id: i2c device id pointer
+ *
+ * This function used to initializes the i2c-client touchscreen
+ * driver and returns integer.
+ */
+static int __devinit bu21013_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct bu21013_ts_data *bu21013_data;
+ struct input_dev *in_dev;
+ const struct bu21013_platform_device *pdata =
+ client->dev.platform_data;
+ int error;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev, "i2c smbus byte data not supported\n");
+ return -EIO;
+ }
+
+ if (!pdata) {
+ dev_err(&client->dev, "platform data not defined\n");
+ return -EINVAL;
+ }
+
+ bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL);
+ in_dev = input_allocate_device();
+ if (!bu21013_data || !in_dev) {
+ dev_err(&client->dev, "device memory alloc failed\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ bu21013_data->in_dev = in_dev;
+ bu21013_data->chip = pdata;
+ bu21013_data->client = client;
+ bu21013_data->touch_stopped = false;
+ init_waitqueue_head(&bu21013_data->wait);
+
+ /* configure the gpio pins */
+ if (pdata->cs_en) {
+ error = pdata->cs_en(pdata->cs_pin);
+ if (error < 0) {
+ dev_err(&client->dev, "chip init failed\n");
+ goto err_free_mem;
+ }
+ }
+
+ /* configure the touch panel controller */
+ error = bu21013_init_chip(bu21013_data);
+ if (error) {
+ dev_err(&client->dev, "error in bu21013 config\n");
+ goto err_cs_disable;
+ }
+
+ /* register the device to input subsystem */
+ in_dev->name = DRIVER_TP;
+ in_dev->id.bustype = BUS_I2C;
+ in_dev->dev.parent = &client->dev;
+
+ __set_bit(EV_SYN, in_dev->evbit);
+ __set_bit(EV_KEY, in_dev->evbit);
+ __set_bit(EV_ABS, in_dev->evbit);
+
+ input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,
+ pdata->x_max_res, 0, 0);
+ input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,
+ pdata->y_max_res, 0, 0);
+ input_set_drvdata(in_dev, bu21013_data);
+
+ error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
+ IRQF_TRIGGER_FALLING | IRQF_SHARED,
+ DRIVER_TP, bu21013_data);
+ if (error) {
+ dev_err(&client->dev, "request irq %d failed\n", pdata->irq);
+ goto err_cs_disable;
+ }
+
+ error = input_register_device(in_dev);
+ if (error) {
+ dev_err(&client->dev, "failed to register input device\n");
+ goto err_free_irq;
+ }
+
+ device_init_wakeup(&client->dev, pdata->wakeup);
+ i2c_set_clientdata(client, bu21013_data);
+
+ return 0;
+
+err_free_irq:
+ bu21013_free_irq(bu21013_data);
+err_cs_disable:
+ pdata->cs_dis(pdata->cs_pin);
+err_free_mem:
+ input_free_device(bu21013_data->in_dev);
+ kfree(bu21013_data);
+
+ return error;
+}
+/**
+ * bu21013_remove() - removes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ *
+ * This function uses to remove the i2c-client
+ * touchscreen driver and returns integer.
+ */
+static int __devexit bu21013_remove(struct i2c_client *client)
+{
+ struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
+
+ bu21013_free_irq(bu21013_data);
+
+ bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin);
+
+ input_unregister_device(bu21013_data->in_dev);
+ kfree(bu21013_data);
+
+ device_init_wakeup(&client->dev, false);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * bu21013_suspend() - suspend the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This function is used to suspend the
+ * touch panel controller and returns integer
+ */
+static int bu21013_suspend(struct device *dev)
+{
+ struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
+ struct i2c_client *client = bu21013_data->client;
+
+ bu21013_data->touch_stopped = true;
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(bu21013_data->chip->irq);
+ else
+ disable_irq(bu21013_data->chip->irq);
+
+ return 0;
+}
+
+/**
+ * bu21013_resume() - resume the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This function is used to resume the touch panel
+ * controller and returns integer.
+ */
+static int bu21013_resume(struct device *dev)
+{
+ struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
+ struct i2c_client *client = bu21013_data->client;
+ int retval;
+
+ retval = bu21013_init_chip(bu21013_data);
+ if (retval < 0) {
+ dev_err(&client->dev, "bu21013 controller config failed\n");
+ return retval;
+ }
+
+ bu21013_data->touch_stopped = false;
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(bu21013_data->chip->irq);
+ else
+ enable_irq(bu21013_data->chip->irq);
+
+ return 0;
+}
+
+static const struct dev_pm_ops bu21013_dev_pm_ops = {
+ .suspend = bu21013_suspend,
+ .resume = bu21013_resume,
+};
+#endif
+
+static const struct i2c_device_id bu21013_id[] = {
+ { DRIVER_TP, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bu21013_id);
+
+static struct i2c_driver bu21013_driver = {
+ .driver = {
+ .name = DRIVER_TP,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &bu21013_dev_pm_ops,
+#endif
+ },
+ .probe = bu21013_probe,
+ .remove = __devexit_p(bu21013_remove),
+ .id_table = bu21013_id,
+};
+
+/**
+ * bu21013_init() - initializes the bu21013 touchscreen driver
+ *
+ * This function used to initializes the bu21013
+ * touchscreen driver and returns integer.
+ */
+static int __init bu21013_init(void)
+{
+ return i2c_add_driver(&bu21013_driver);
+}
+
+/**
+ * bu21013_exit() - de-initializes the bu21013 touchscreen driver
+ *
+ * This function uses to de-initializes the bu21013
+ * touchscreen driver and returns none.
+ */
+static void __exit bu21013_exit(void)
+{
+ i2c_del_driver(&bu21013_driver);
+}
+
+module_init(bu21013_init);
+module_exit(bu21013_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>");
+MODULE_DESCRIPTION("bu21013 touch screen controller driver");
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
index 5ec0946938fe..d0c3a7229adf 100644
--- a/drivers/input/touchscreen/cy8ctmg110_ts.c
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -206,9 +206,9 @@ static int __devinit cy8ctmg110_probe(struct i2c_client *client,
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X,
- CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 0, 0);
+ CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
input_set_abs_params(input_dev, ABS_Y,
- CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 0, 0);
+ CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
if (ts->reset_pin) {
err = gpio_request(ts->reset_pin, NULL);
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
index a89700e7ace4..498bd62af09a 100644
--- a/drivers/input/touchscreen/hp680_ts_input.c
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -107,8 +107,7 @@ static int __init hp680_ts_init(void)
return 0;
fail2: free_irq(HP680_TS_IRQ, NULL);
- cancel_delayed_work(&work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&work);
fail1: input_free_device(hp680_ts_dev);
return err;
}
@@ -116,8 +115,7 @@ static int __init hp680_ts_init(void)
static void __exit hp680_ts_exit(void)
{
free_irq(HP680_TS_IRQ, NULL);
- cancel_delayed_work(&work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&work);
input_unregister_device(hp680_ts_dev);
}
diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c
new file mode 100644
index 000000000000..c0307b22d86f
--- /dev/null
+++ b/drivers/input/touchscreen/intel-mid-touch.c
@@ -0,0 +1,687 @@
+/*
+ * Intel MID Resistive Touch Screen Driver
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
+ * Ramesh Agarwal (ramesh.agarwal@intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * TODO:
+ * review conversion of r/m/w sequences
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/param.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <asm/intel_scu_ipc.h>
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_ID1 0x00 /* PMIC ID1 register */
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_INT 0x04 /* PMIC interrupt register */
+#define PMIC_REG_MINT 0x05 /* PMIC interrupt mask register */
+
+/* ADC Interrupt registers */
+#define PMIC_REG_ADCINT 0x5F /* ADC interrupt register */
+#define PMIC_REG_MADCINT 0x60 /* ADC interrupt mask register */
+
+/* ADC Control registers */
+#define PMIC_REG_ADCCNTL1 0x61 /* ADC control register */
+
+/* ADC Channel Selection registers */
+#define PMICADDR0 0xA4
+#define END_OF_CHANNEL 0x1F
+
+/* ADC Result register */
+#define PMIC_REG_ADCSNS0H 0x64
+
+/* ADC channels for touch screen */
+#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */
+#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */
+#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */
+#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */
+
+/* Touch screen channel BIAS constants */
+#define MRST_XBIAS 0x20
+#define MRST_YBIAS 0x40
+#define MRST_ZBIAS 0x80
+
+/* Touch screen coordinates */
+#define MRST_X_MIN 10
+#define MRST_X_MAX 1024
+#define MRST_X_FUZZ 5
+#define MRST_Y_MIN 10
+#define MRST_Y_MAX 1024
+#define MRST_Y_FUZZ 5
+#define MRST_PRESSURE_MIN 0
+#define MRST_PRESSURE_NOMINAL 50
+#define MRST_PRESSURE_MAX 100
+
+#define WAIT_ADC_COMPLETION 10 /* msec */
+
+/* PMIC ADC round robin delays */
+#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
+#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */
+
+/* PMIC Vendor Identifiers */
+#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */
+#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
+#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
+#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
+
+/* Touch screen device structure */
+struct mrstouch_dev {
+ struct device *dev; /* device associated with touch screen */
+ struct input_dev *input;
+ char phys[32];
+ u16 asr; /* Address selection register */
+ int irq;
+ unsigned int vendor; /* PMIC vendor */
+ unsigned int rev; /* PMIC revision */
+
+ int (*read_prepare)(struct mrstouch_dev *tsdev);
+ int (*read)(struct mrstouch_dev *tsdev, u16 *x, u16 *y, u16 *z);
+ int (*read_finish)(struct mrstouch_dev *tsdev);
+};
+
+
+/*************************** NEC and Maxim Interface ************************/
+
+static int mrstouch_nec_adc_read_prepare(struct mrstouch_dev *tsdev)
+{
+ return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0, 0x20);
+}
+
+/*
+ * Enables PENDET interrupt.
+ */
+static int mrstouch_nec_adc_read_finish(struct mrstouch_dev *tsdev)
+{
+ int err;
+
+ err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x20, 0x20);
+ if (!err)
+ err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, 0, 0x05);
+
+ return err;
+}
+
+/*
+ * Reads PMIC ADC touch screen result
+ * Reads ADC storage registers for higher 7 and lower 3 bits and
+ * converts the two readings into a single value and turns off gain bit
+ */
+static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
+{
+ int err;
+ u16 result;
+ u32 res;
+
+ result = PMIC_REG_ADCSNS0H + offset;
+
+ if (chan == MRST_TS_CHAN12)
+ result += 4;
+
+ err = intel_scu_ipc_ioread32(result, &res);
+ if (err)
+ return err;
+
+ /* Mash the bits up */
+
+ *vp = (res & 0xFF) << 3; /* Highest 7 bits */
+ *vp |= (res >> 8) & 0x07; /* Lower 3 bits */
+ *vp &= 0x3FF;
+
+ res >>= 16;
+
+ *vm = (res & 0xFF) << 3; /* Highest 7 bits */
+ *vm |= (res >> 8) & 0x07; /* Lower 3 bits */
+ *vm &= 0x3FF;
+
+ return 0;
+}
+
+/*
+ * Enables X, Y and Z bias values
+ * Enables YPYM for X channels and XPXM for Y channels
+ */
+static int mrstouch_ts_bias_set(uint offset, uint bias)
+{
+ int count;
+ u16 chan, start;
+ u16 reg[4];
+ u8 data[4];
+
+ chan = PMICADDR0 + offset;
+ start = MRST_TS_CHAN10;
+
+ for (count = 0; count <= 3; count++) {
+ reg[count] = chan++;
+ data[count] = bias | (start + count);
+ }
+
+ return intel_scu_ipc_writev(reg, data, 4);
+}
+
+/* To read touch screen channel values */
+static int mrstouch_nec_adc_read(struct mrstouch_dev *tsdev,
+ u16 *x, u16 *y, u16 *z)
+{
+ int err;
+ u16 xm, ym, zm;
+
+ /* configure Y bias for X channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, MRST_YBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read x+ and x- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, x, &xm);
+ if (err)
+ goto ipc_error;
+
+ /* configure x bias for y channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, MRST_XBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read y+ and y- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, y, &ym);
+ if (err)
+ goto ipc_error;
+
+ /* configure z bias for x and y channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, MRST_ZBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read z+ and z- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, z, &zm);
+ if (err)
+ goto ipc_error;
+
+ return 0;
+
+ipc_error:
+ dev_err(tsdev->dev, "ipc error during adc read\n");
+ return err;
+}
+
+
+/*************************** Freescale Interface ************************/
+
+static int mrstouch_fs_adc_read_prepare(struct mrstouch_dev *tsdev)
+{
+ int err, count;
+ u16 chan;
+ u16 reg[5];
+ u8 data[5];
+
+ /* Stop the ADC */
+ err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
+ if (err)
+ goto ipc_error;
+
+ chan = PMICADDR0 + tsdev->asr;
+
+ /* Set X BIAS */
+ for (count = 0; count <= 3; count++) {
+ reg[count] = chan++;
+ data[count] = 0x2A;
+ }
+ reg[count] = chan++; /* Dummy */
+ data[count] = 0;
+
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* Set Y BIAS */
+ for (count = 0; count <= 3; count++) {
+ reg[count] = chan++;
+ data[count] = 0x4A;
+ }
+ reg[count] = chan++; /* Dummy */
+ data[count] = 0;
+
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* Set Z BIAS */
+ err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ return 0;
+
+ipc_error:
+ dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+ return err;
+}
+
+static int mrstouch_fs_adc_read(struct mrstouch_dev *tsdev,
+ u16 *x, u16 *y, u16 *z)
+{
+ int err;
+ u16 result;
+ u16 reg[4];
+ u8 data[4];
+
+ result = PMIC_REG_ADCSNS0H + tsdev->asr;
+
+ reg[0] = result + 4;
+ reg[1] = result + 5;
+ reg[2] = result + 16;
+ reg[3] = result + 17;
+
+ err = intel_scu_ipc_readv(reg, data, 4);
+ if (err)
+ goto ipc_error;
+
+ *x = data[0] << 3; /* Higher 7 bits */
+ *x |= data[1] & 0x7; /* Lower 3 bits */
+ *x &= 0x3FF;
+
+ *y = data[2] << 3; /* Higher 7 bits */
+ *y |= data[3] & 0x7; /* Lower 3 bits */
+ *y &= 0x3FF;
+
+ /* Read Z value */
+ reg[0] = result + 28;
+ reg[1] = result + 29;
+
+ err = intel_scu_ipc_readv(reg, data, 4);
+ if (err)
+ goto ipc_error;
+
+ *z = data[0] << 3; /* Higher 7 bits */
+ *z |= data[1] & 0x7; /* Lower 3 bits */
+ *z &= 0x3FF;
+
+ return 0;
+
+ipc_error:
+ dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+ return err;
+}
+
+static int mrstouch_fs_adc_read_finish(struct mrstouch_dev *tsdev)
+{
+ int err, count;
+ u16 chan;
+ u16 reg[5];
+ u8 data[5];
+
+ /* Clear all TS channels */
+ chan = PMICADDR0 + tsdev->asr;
+ for (count = 0; count <= 4; count++) {
+ reg[count] = chan++;
+ data[count] = 0;
+ }
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ for (count = 0; count <= 4; count++) {
+ reg[count] = chan++;
+ data[count] = 0;
+ }
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000);
+ if (err)
+ goto ipc_error;
+
+ /* Start ADC */
+ err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
+ if (err)
+ goto ipc_error;
+
+ return 0;
+
+ipc_error:
+ dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+ return err;
+}
+
+static void mrstouch_report_event(struct input_dev *input,
+ unsigned int x, unsigned int y, unsigned int z)
+{
+ if (z > MRST_PRESSURE_NOMINAL) {
+ /* Pen touched, report button touch and coordinates */
+ input_report_key(input, BTN_TOUCH, 1);
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ } else {
+ input_report_key(input, BTN_TOUCH, 0);
+ }
+
+ input_report_abs(input, ABS_PRESSURE, z);
+ input_sync(input);
+}
+
+/* PENDET interrupt handler */
+static irqreturn_t mrstouch_pendet_irq(int irq, void *dev_id)
+{
+ struct mrstouch_dev *tsdev = dev_id;
+ u16 x, y, z;
+
+ /*
+ * Should we lower thread priority? Probably not, since we are
+ * not spinning but sleeping...
+ */
+
+ if (tsdev->read_prepare(tsdev))
+ goto out;
+
+ do {
+ if (tsdev->read(tsdev, &x, &y, &z))
+ break;
+
+ mrstouch_report_event(tsdev->input, x, y, z);
+ } while (z > MRST_PRESSURE_NOMINAL);
+
+ tsdev->read_finish(tsdev);
+
+out:
+ return IRQ_HANDLED;
+}
+
+/* Utility to read PMIC ID */
+static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev)
+{
+ int err;
+ u8 r;
+
+ err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
+ if (err)
+ return err;
+
+ *vendor = r & 0x7;
+ *rev = (r >> 3) & 0x7;
+
+ return 0;
+}
+
+/*
+ * Parse ADC channels to find end of the channel configured by other ADC user
+ * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
+ */
+static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
+{
+ int err, i, found;
+ u8 r8;
+
+ found = -1;
+
+ for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
+ if (found >= 0)
+ break;
+
+ err = intel_scu_ipc_ioread8(PMICADDR0 + i, &r8);
+ if (err)
+ return err;
+
+ if (r8 == END_OF_CHANNEL) {
+ found = i;
+ break;
+ }
+ }
+ if (found < 0)
+ return 0;
+
+ if (tsdev->vendor == PMIC_VENDOR_FS) {
+ if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
+ return -ENOSPC;
+ } else {
+ if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
+ return -ENOSPC;
+ }
+ return found;
+}
+
+
+/*
+ * Writes touch screen channels to ADC address selection registers
+ */
+static int __devinit mrstouch_ts_chan_set(uint offset)
+{
+ u16 chan;
+
+ int ret, count;
+
+ chan = PMICADDR0 + offset;
+ for (count = 0; count <= 3; count++) {
+ ret = intel_scu_ipc_iowrite8(chan++, MRST_TS_CHAN10 + count);
+ if (ret)
+ return ret;
+ }
+ return intel_scu_ipc_iowrite8(chan++, END_OF_CHANNEL);
+}
+
+/* Initialize ADC */
+static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev)
+{
+ int err, start;
+ u8 ra, rm;
+
+ err = mrstouch_read_pmic_id(&tsdev->vendor, &tsdev->rev);
+ if (err) {
+ dev_err(tsdev->dev, "Unable to read PMIC id\n");
+ return err;
+ }
+
+ switch (tsdev->vendor) {
+ case PMIC_VENDOR_NEC:
+ case PMIC_VENDOR_MAXIM:
+ tsdev->read_prepare = mrstouch_nec_adc_read_prepare;
+ tsdev->read = mrstouch_nec_adc_read;
+ tsdev->read_finish = mrstouch_nec_adc_read_finish;
+ break;
+
+ case PMIC_VENDOR_FS:
+ tsdev->read_prepare = mrstouch_fs_adc_read_prepare;
+ tsdev->read = mrstouch_fs_adc_read;
+ tsdev->read_finish = mrstouch_fs_adc_read_finish;
+ break;
+
+ default:
+ dev_err(tsdev->dev,
+ "Unsupported touchscreen: %d\n", tsdev->vendor);
+ return -ENXIO;
+ }
+
+ start = mrstouch_chan_parse(tsdev);
+ if (start < 0) {
+ dev_err(tsdev->dev, "Unable to parse channels\n");
+ return start;
+ }
+
+ tsdev->asr = start;
+
+ /*
+ * ADC power on, start, enable PENDET and set loop delay
+ * ADC loop delay is set to 4.5 ms approximately
+ * Loop delay more than this results in jitter in adc readings
+ * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
+ * interrupt generation sometimes.
+ */
+
+ if (tsdev->vendor == PMIC_VENDOR_FS) {
+ ra = 0xE0 | ADC_LOOP_DELAY0;
+ rm = 0x5;
+ } else {
+ /* NEC and MAXIm not consistent with loop delay 0 */
+ ra = 0xE0 | ADC_LOOP_DELAY1;
+ rm = 0x0;
+
+ /* configure touch screen channels */
+ err = mrstouch_ts_chan_set(tsdev->asr);
+ if (err)
+ return err;
+ }
+
+ err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
+ if (err)
+ return err;
+
+ err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+
+/* Probe function for touch screen driver */
+static int __devinit mrstouch_probe(struct platform_device *pdev)
+{
+ struct mrstouch_dev *tsdev;
+ struct input_dev *input;
+ int err;
+ int irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no interrupt assigned\n");
+ return -EINVAL;
+ }
+
+ tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!tsdev || !input) {
+ dev_err(&pdev->dev, "unable to allocate memory\n");
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ tsdev->dev = &pdev->dev;
+ tsdev->input = input;
+ tsdev->irq = irq;
+
+ snprintf(tsdev->phys, sizeof(tsdev->phys),
+ "%s/input0", dev_name(tsdev->dev));
+
+ err = mrstouch_adc_init(tsdev);
+ if (err) {
+ dev_err(&pdev->dev, "ADC initialization failed\n");
+ goto err_free_mem;
+ }
+
+ input->name = "mrst_touchscreen";
+ input->phys = tsdev->phys;
+ input->dev.parent = tsdev->dev;
+
+ input->id.vendor = tsdev->vendor;
+ input->id.version = tsdev->rev;
+
+ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(tsdev->input, ABS_X,
+ MRST_X_MIN, MRST_X_MAX, MRST_X_FUZZ, 0);
+ input_set_abs_params(tsdev->input, ABS_Y,
+ MRST_Y_MIN, MRST_Y_MAX, MRST_Y_FUZZ, 0);
+ input_set_abs_params(tsdev->input, ABS_PRESSURE,
+ MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
+
+ err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq,
+ 0, "mrstouch", tsdev);
+ if (err) {
+ dev_err(tsdev->dev, "unable to allocate irq\n");
+ goto err_free_mem;
+ }
+
+ err = input_register_device(tsdev->input);
+ if (err) {
+ dev_err(tsdev->dev, "unable to register input device\n");
+ goto err_free_irq;
+ }
+
+ platform_set_drvdata(pdev, tsdev);
+ return 0;
+
+err_free_irq:
+ free_irq(tsdev->irq, tsdev);
+err_free_mem:
+ input_free_device(input);
+ kfree(tsdev);
+ return err;
+}
+
+static int __devexit mrstouch_remove(struct platform_device *pdev)
+{
+ struct mrstouch_dev *tsdev = platform_get_drvdata(pdev);
+
+ free_irq(tsdev->irq, tsdev);
+ input_unregister_device(tsdev->input);
+ kfree(tsdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver mrstouch_driver = {
+ .driver = {
+ .name = "pmic_touch",
+ .owner = THIS_MODULE,
+ },
+ .probe = mrstouch_probe,
+ .remove = __devexit_p(mrstouch_remove),
+};
+
+static int __init mrstouch_init(void)
+{
+ return platform_driver_register(&mrstouch_driver);
+}
+module_init(mrstouch_init);
+
+static void __exit mrstouch_exit(void)
+{
+ platform_driver_unregister(&mrstouch_driver);
+}
+module_exit(mrstouch_exit);
+
+MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
+MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c
new file mode 100644
index 000000000000..dcf803f5a1f7
--- /dev/null
+++ b/drivers/input/touchscreen/lpc32xx_ts.c
@@ -0,0 +1,411 @@
+/*
+ * LPC32xx built-in touchscreen driver
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/*
+ * Touchscreen controller register offsets
+ */
+#define LPC32XX_TSC_STAT 0x00
+#define LPC32XX_TSC_SEL 0x04
+#define LPC32XX_TSC_CON 0x08
+#define LPC32XX_TSC_FIFO 0x0C
+#define LPC32XX_TSC_DTR 0x10
+#define LPC32XX_TSC_RTR 0x14
+#define LPC32XX_TSC_UTR 0x18
+#define LPC32XX_TSC_TTR 0x1C
+#define LPC32XX_TSC_DXP 0x20
+#define LPC32XX_TSC_MIN_X 0x24
+#define LPC32XX_TSC_MAX_X 0x28
+#define LPC32XX_TSC_MIN_Y 0x2C
+#define LPC32XX_TSC_MAX_Y 0x30
+#define LPC32XX_TSC_AUX_UTR 0x34
+#define LPC32XX_TSC_AUX_MIN 0x38
+#define LPC32XX_TSC_AUX_MAX 0x3C
+
+#define LPC32XX_TSC_STAT_FIFO_OVRRN (1 << 8)
+#define LPC32XX_TSC_STAT_FIFO_EMPTY (1 << 7)
+
+#define LPC32XX_TSC_SEL_DEFVAL 0x0284
+
+#define LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 (0x1 << 11)
+#define LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(s) ((10 - (s)) << 7)
+#define LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(s) ((10 - (s)) << 4)
+#define LPC32XX_TSC_ADCCON_POWER_UP (1 << 2)
+#define LPC32XX_TSC_ADCCON_AUTO_EN (1 << 0)
+
+#define LPC32XX_TSC_FIFO_TS_P_LEVEL (1 << 31)
+#define LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(x) (((x) & 0x03FF0000) >> 16)
+#define LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(y) ((y) & 0x000003FF)
+
+#define LPC32XX_TSC_ADCDAT_VALUE_MASK 0x000003FF
+
+#define LPC32XX_TSC_MIN_XY_VAL 0x0
+#define LPC32XX_TSC_MAX_XY_VAL 0x3FF
+
+#define MOD_NAME "ts-lpc32xx"
+
+#define tsc_readl(dev, reg) \
+ __raw_readl((dev)->tsc_base + (reg))
+#define tsc_writel(dev, reg, val) \
+ __raw_writel((val), (dev)->tsc_base + (reg))
+
+struct lpc32xx_tsc {
+ struct input_dev *dev;
+ void __iomem *tsc_base;
+ int irq;
+ struct clk *clk;
+};
+
+static void lpc32xx_fifo_clear(struct lpc32xx_tsc *tsc)
+{
+ while (!(tsc_readl(tsc, LPC32XX_TSC_STAT) &
+ LPC32XX_TSC_STAT_FIFO_EMPTY))
+ tsc_readl(tsc, LPC32XX_TSC_FIFO);
+}
+
+static irqreturn_t lpc32xx_ts_interrupt(int irq, void *dev_id)
+{
+ u32 tmp, rv[4], xs[4], ys[4];
+ int idx;
+ struct lpc32xx_tsc *tsc = dev_id;
+ struct input_dev *input = tsc->dev;
+
+ tmp = tsc_readl(tsc, LPC32XX_TSC_STAT);
+
+ if (tmp & LPC32XX_TSC_STAT_FIFO_OVRRN) {
+ /* FIFO overflow - throw away samples */
+ lpc32xx_fifo_clear(tsc);
+ return IRQ_HANDLED;
+ }
+
+ /*
+ * Gather and normalize 4 samples. Pen-up events may have less
+ * than 4 samples, but its ok to pop 4 and let the last sample
+ * pen status check drop the samples.
+ */
+ idx = 0;
+ while (idx < 4 &&
+ !(tsc_readl(tsc, LPC32XX_TSC_STAT) &
+ LPC32XX_TSC_STAT_FIFO_EMPTY)) {
+ tmp = tsc_readl(tsc, LPC32XX_TSC_FIFO);
+ xs[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
+ LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(tmp);
+ ys[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
+ LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(tmp);
+ rv[idx] = tmp;
+ idx++;
+ }
+
+ /* Data is only valid if pen is still down in last sample */
+ if (!(rv[3] & LPC32XX_TSC_FIFO_TS_P_LEVEL) && idx == 4) {
+ /* Use average of 2nd and 3rd sample for position */
+ input_report_abs(input, ABS_X, (xs[1] + xs[2]) / 2);
+ input_report_abs(input, ABS_Y, (ys[1] + ys[2]) / 2);
+ input_report_key(input, BTN_TOUCH, 1);
+ } else {
+ input_report_key(input, BTN_TOUCH, 0);
+ }
+
+ input_sync(input);
+
+ return IRQ_HANDLED;
+}
+
+static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc)
+{
+ /* Disable auto mode */
+ tsc_writel(tsc, LPC32XX_TSC_CON,
+ tsc_readl(tsc, LPC32XX_TSC_CON) &
+ ~LPC32XX_TSC_ADCCON_AUTO_EN);
+
+ clk_disable(tsc->clk);
+}
+
+static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
+{
+ u32 tmp;
+
+ clk_enable(tsc->clk);
+
+ tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP;
+
+ /* Set the TSC FIFO depth to 4 samples @ 10-bits per sample (max) */
+ tmp = LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 |
+ LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(10) |
+ LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(10);
+ tsc_writel(tsc, LPC32XX_TSC_CON, tmp);
+
+ /* These values are all preset */
+ tsc_writel(tsc, LPC32XX_TSC_SEL, LPC32XX_TSC_SEL_DEFVAL);
+ tsc_writel(tsc, LPC32XX_TSC_MIN_X, LPC32XX_TSC_MIN_XY_VAL);
+ tsc_writel(tsc, LPC32XX_TSC_MAX_X, LPC32XX_TSC_MAX_XY_VAL);
+ tsc_writel(tsc, LPC32XX_TSC_MIN_Y, LPC32XX_TSC_MIN_XY_VAL);
+ tsc_writel(tsc, LPC32XX_TSC_MAX_Y, LPC32XX_TSC_MAX_XY_VAL);
+
+ /* Aux support is not used */
+ tsc_writel(tsc, LPC32XX_TSC_AUX_UTR, 0);
+ tsc_writel(tsc, LPC32XX_TSC_AUX_MIN, 0);
+ tsc_writel(tsc, LPC32XX_TSC_AUX_MAX, 0);
+
+ /*
+ * Set sample rate to about 240Hz per X/Y pair. A single measurement
+ * consists of 4 pairs which gives about a 60Hz sample rate based on
+ * a stable 32768Hz clock source. Values are in clocks.
+ * Rate is (32768 / (RTR + XCONV + RTR + YCONV + DXP + TTR + UTR) / 4
+ */
+ tsc_writel(tsc, LPC32XX_TSC_RTR, 0x2);
+ tsc_writel(tsc, LPC32XX_TSC_DTR, 0x2);
+ tsc_writel(tsc, LPC32XX_TSC_TTR, 0x10);
+ tsc_writel(tsc, LPC32XX_TSC_DXP, 0x4);
+ tsc_writel(tsc, LPC32XX_TSC_UTR, 88);
+
+ lpc32xx_fifo_clear(tsc);
+
+ /* Enable automatic ts event capture */
+ tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN);
+}
+
+static int lpc32xx_ts_open(struct input_dev *dev)
+{
+ struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
+
+ lpc32xx_setup_tsc(tsc);
+
+ return 0;
+}
+
+static void lpc32xx_ts_close(struct input_dev *dev)
+{
+ struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
+
+ lpc32xx_stop_tsc(tsc);
+}
+
+static int __devinit lpc32xx_ts_probe(struct platform_device *pdev)
+{
+ struct lpc32xx_tsc *tsc;
+ struct input_dev *input;
+ struct resource *res;
+ resource_size_t size;
+ int irq;
+ int error;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Can't get memory resource\n");
+ return -ENOENT;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Can't get interrupt resource\n");
+ return irq;
+ }
+
+ tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!tsc || !input) {
+ dev_err(&pdev->dev, "failed allocating memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ tsc->dev = input;
+ tsc->irq = irq;
+
+ size = resource_size(res);
+
+ if (!request_mem_region(res->start, size, pdev->name)) {
+ dev_err(&pdev->dev, "TSC registers are not free\n");
+ error = -EBUSY;
+ goto err_free_mem;
+ }
+
+ tsc->tsc_base = ioremap(res->start, size);
+ if (!tsc->tsc_base) {
+ dev_err(&pdev->dev, "Can't map memory\n");
+ error = -ENOMEM;
+ goto err_release_mem;
+ }
+
+ tsc->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(tsc->clk)) {
+ dev_err(&pdev->dev, "failed getting clock\n");
+ error = PTR_ERR(tsc->clk);
+ goto err_unmap;
+ }
+
+ input->name = MOD_NAME;
+ input->phys = "lpc32xx/input0";
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0002;
+ input->id.version = 0x0100;
+ input->dev.parent = &pdev->dev;
+ input->open = lpc32xx_ts_open;
+ input->close = lpc32xx_ts_close;
+
+ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,
+ LPC32XX_TSC_MAX_XY_VAL, 0, 0);
+ input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,
+ LPC32XX_TSC_MAX_XY_VAL, 0, 0);
+
+ input_set_drvdata(input, tsc);
+
+ error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
+ IRQF_DISABLED, pdev->name, tsc);
+ if (error) {
+ dev_err(&pdev->dev, "failed requesting interrupt\n");
+ goto err_put_clock;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev, "failed registering input device\n");
+ goto err_free_irq;
+ }
+
+ platform_set_drvdata(pdev, tsc);
+ device_init_wakeup(&pdev->dev, 1);
+
+ return 0;
+
+err_free_irq:
+ free_irq(tsc->irq, tsc);
+err_put_clock:
+ clk_put(tsc->clk);
+err_unmap:
+ iounmap(tsc->tsc_base);
+err_release_mem:
+ release_mem_region(res->start, size);
+err_free_mem:
+ input_free_device(input);
+ kfree(tsc);
+
+ return error;
+}
+
+static int __devexit lpc32xx_ts_remove(struct platform_device *pdev)
+{
+ struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ device_init_wakeup(&pdev->dev, 0);
+ free_irq(tsc->irq, tsc);
+
+ input_unregister_device(tsc->dev);
+
+ clk_put(tsc->clk);
+
+ iounmap(tsc->tsc_base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(tsc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_ts_suspend(struct device *dev)
+{
+ struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
+ struct input_dev *input = tsc->dev;
+
+ /*
+ * Suspend and resume can be called when the device hasn't been
+ * enabled. If there are no users that have the device open, then
+ * avoid calling the TSC stop and start functions as the TSC
+ * isn't yet clocked.
+ */
+ mutex_lock(&input->mutex);
+
+ if (input->users) {
+ if (device_may_wakeup(dev))
+ enable_irq_wake(tsc->irq);
+ else
+ lpc32xx_stop_tsc(tsc);
+ }
+
+ mutex_unlock(&input->mutex);
+
+ return 0;
+}
+
+static int lpc32xx_ts_resume(struct device *dev)
+{
+ struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
+ struct input_dev *input = tsc->dev;
+
+ mutex_lock(&input->mutex);
+
+ if (input->users) {
+ if (device_may_wakeup(dev))
+ disable_irq_wake(tsc->irq);
+ else
+ lpc32xx_setup_tsc(tsc);
+ }
+
+ mutex_unlock(&input->mutex);
+
+ return 0;
+}
+
+static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
+ .suspend = lpc32xx_ts_suspend,
+ .resume = lpc32xx_ts_resume,
+};
+#define LPC32XX_TS_PM_OPS (&lpc32xx_ts_pm_ops)
+#else
+#define LPC32XX_TS_PM_OPS NULL
+#endif
+
+static struct platform_driver lpc32xx_ts_driver = {
+ .probe = lpc32xx_ts_probe,
+ .remove = __devexit_p(lpc32xx_ts_remove),
+ .driver = {
+ .name = MOD_NAME,
+ .owner = THIS_MODULE,
+ .pm = LPC32XX_TS_PM_OPS,
+ },
+};
+
+static int __init lpc32xx_ts_init(void)
+{
+ return platform_driver_register(&lpc32xx_ts_driver);
+}
+module_init(lpc32xx_ts_init);
+
+static void __exit lpc32xx_ts_exit(void)
+{
+ platform_driver_unregister(&lpc32xx_ts_driver);
+}
+module_exit(lpc32xx_ts_exit);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com");
+MODULE_DESCRIPTION("LPC32XX TSC Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lpc32xx_ts");
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
index 6085d12fd561..8feb7f3c8be1 100644
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ b/drivers/input/touchscreen/s3c2410_ts.c
@@ -350,7 +350,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev)
err_tcirq:
free_irq(ts.irq_tc, ts.input);
err_inputdev:
- input_unregister_device(ts.input);
+ input_free_device(ts.input);
err_iomap:
iounmap(ts.io);
err_clk:
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index 656148ec0027..ae88e13c99ff 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -268,7 +268,7 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev)
struct stmpe_touch *ts;
struct input_dev *idev;
struct stmpe_ts_platform_data *ts_pdata = NULL;
- int ret = 0;
+ int ret;
int ts_irq;
ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
@@ -276,12 +276,16 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev)
return ts_irq;
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
- if (!ts)
+ if (!ts) {
+ ret = -ENOMEM;
goto err_out;
+ }
idev = input_allocate_device();
- if (!idev)
+ if (!idev) {
+ ret = -ENOMEM;
goto err_free_ts;
+ }
platform_set_drvdata(pdev, ts);
ts->stmpe = stmpe;
@@ -361,7 +365,6 @@ static int __devexit stmpe_ts_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
input_unregister_device(ts->idev);
- input_free_device(ts->idev);
kfree(ts);
diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c
index a644d18c04dc..c8c136cf7bbc 100644
--- a/drivers/input/touchscreen/tps6507x-ts.c
+++ b/drivers/input/touchscreen/tps6507x-ts.c
@@ -335,6 +335,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
dev_err(tsc->dev, "schedule failed");
goto err2;
}
+ platform_set_drvdata(pdev, tps6507x_dev);
return 0;
@@ -358,7 +359,7 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&tsc->work);
destroy_workqueue(tsc->wq);
- input_free_device(input_dev);
+ input_unregister_device(input_dev);
tps6507x_dev->ts = NULL;
kfree(tsc);
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index be23780e8a3e..80467f262331 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -265,7 +265,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tsc2007 *ts;
- struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;
+ struct tsc2007_platform_data *pdata = client->dev.platform_data;
struct input_dev *input_dev;
int err;
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 56dc35c94bb1..9ae4c7b16ba7 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -2,6 +2,7 @@
* Wacom W8001 penabled serial touchscreen driver
*
* Copyright (c) 2008 Jaya Kumar
+ * Copyright (c) 2010 Red Hat, Inc.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
@@ -30,11 +31,24 @@ MODULE_LICENSE("GPL");
#define W8001_LEAD_BYTE 0x80
#define W8001_TAB_MASK 0x40
#define W8001_TAB_BYTE 0x40
+/* set in first byte of touch data packets */
+#define W8001_TOUCH_MASK (0x10 | W8001_LEAD_MASK)
+#define W8001_TOUCH_BYTE (0x10 | W8001_LEAD_BYTE)
#define W8001_QUERY_PACKET 0x20
#define W8001_CMD_START '1'
#define W8001_CMD_QUERY '*'
+#define W8001_CMD_TOUCHQUERY '%'
+
+/* length of data packets in bytes, depends on device. */
+#define W8001_PKTLEN_TOUCH93 5
+#define W8001_PKTLEN_TOUCH9A 7
+#define W8001_PKTLEN_TPCPEN 9
+#define W8001_PKTLEN_TPCCTL 11 /* control packet */
+#define W8001_PKTLEN_TOUCH2FG 13
+
+#define MAX_TRACKING_ID 0xFF /* arbitrarily chosen */
struct w8001_coord {
u8 rdy;
@@ -48,6 +62,15 @@ struct w8001_coord {
u8 tilt_y;
};
+/* touch query reply packet */
+struct w8001_touch_query {
+ u8 panel_res;
+ u8 capacity_res;
+ u8 sensor_id;
+ u16 x;
+ u16 y;
+};
+
/*
* Per-touchscreen data.
*/
@@ -62,6 +85,9 @@ struct w8001 {
unsigned char response[W8001_MAX_LENGTH];
unsigned char data[W8001_MAX_LENGTH];
char phys[32];
+ int type;
+ unsigned int pktlen;
+ int trkid[2];
};
static void parse_data(u8 *data, struct w8001_coord *coord)
@@ -88,11 +114,98 @@ static void parse_data(u8 *data, struct w8001_coord *coord)
coord->tilt_y = data[8] & 0x7F;
}
+static void parse_touch(struct w8001 *w8001)
+{
+ static int trkid;
+ struct input_dev *dev = w8001->dev;
+ unsigned char *data = w8001->data;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ input_mt_slot(dev, i);
+
+ if (data[0] & (1 << i)) {
+ int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]);
+ int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]);
+ /* data[5,6] and [11,12] is finger capacity */
+
+ input_report_abs(dev, ABS_MT_POSITION_X, x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+ if (w8001->trkid[i] < 0)
+ w8001->trkid[i] = trkid++ & MAX_TRACKING_ID;
+ } else {
+ w8001->trkid[i] = -1;
+ }
+ input_report_abs(dev, ABS_MT_TRACKING_ID, w8001->trkid[i]);
+ }
+
+ input_sync(dev);
+}
+
+static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
+{
+ memset(query, 0, sizeof(*query));
+
+ query->panel_res = data[1];
+ query->sensor_id = data[2] & 0x7;
+ query->capacity_res = data[7];
+
+ query->x = data[3] << 9;
+ query->x |= data[4] << 2;
+ query->x |= (data[2] >> 5) & 0x3;
+
+ query->y = data[5] << 9;
+ query->y |= data[6] << 2;
+ query->y |= (data[2] >> 3) & 0x3;
+}
+
+static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
+{
+ struct input_dev *dev = w8001->dev;
+
+ /*
+ * We have 1 bit for proximity (rdy) and 3 bits for tip, side,
+ * side2/eraser. If rdy && f2 are set, this can be either pen + side2,
+ * or eraser. assume
+ * - if dev is already in proximity and f2 is toggled → pen + side2
+ * - if dev comes into proximity with f2 set → eraser
+ * If f2 disappears after assuming eraser, fake proximity out for
+ * eraser and in for pen.
+ */
+
+ if (!w8001->type) {
+ w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ } else if (w8001->type == BTN_TOOL_RUBBER) {
+ if (!coord->f2) {
+ input_report_abs(dev, ABS_PRESSURE, 0);
+ input_report_key(dev, BTN_TOUCH, 0);
+ input_report_key(dev, BTN_STYLUS, 0);
+ input_report_key(dev, BTN_STYLUS2, 0);
+ input_report_key(dev, BTN_TOOL_RUBBER, 0);
+ input_sync(dev);
+ w8001->type = BTN_TOOL_PEN;
+ }
+ } else {
+ input_report_key(dev, BTN_STYLUS2, coord->f2);
+ }
+
+ input_report_abs(dev, ABS_X, coord->x);
+ input_report_abs(dev, ABS_Y, coord->y);
+ input_report_abs(dev, ABS_PRESSURE, coord->pen_pressure);
+ input_report_key(dev, BTN_TOUCH, coord->tsw);
+ input_report_key(dev, BTN_STYLUS, coord->f1);
+ input_report_key(dev, w8001->type, coord->rdy);
+ input_sync(dev);
+
+ if (!coord->rdy)
+ w8001->type = 0;
+}
+
static irqreturn_t w8001_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct w8001 *w8001 = serio_get_drvdata(serio);
- struct input_dev *dev = w8001->dev;
struct w8001_coord coord;
unsigned char tmp;
@@ -105,26 +218,45 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
}
break;
- case 8:
+ case W8001_PKTLEN_TOUCH93 - 1:
+ case W8001_PKTLEN_TOUCH9A - 1:
+ /* ignore one-finger touch packet. */
+ if (w8001->pktlen == w8001->idx)
+ w8001->idx = 0;
+ break;
+
+ /* Pen coordinates packet */
+ case W8001_PKTLEN_TPCPEN - 1:
tmp = w8001->data[0] & W8001_TAB_MASK;
if (unlikely(tmp == W8001_TAB_BYTE))
break;
+ tmp = (w8001->data[0] & W8001_TOUCH_BYTE);
+ if (tmp == W8001_TOUCH_BYTE)
+ break;
+
w8001->idx = 0;
parse_data(w8001->data, &coord);
- input_report_abs(dev, ABS_X, coord.x);
- input_report_abs(dev, ABS_Y, coord.y);
- input_report_abs(dev, ABS_PRESSURE, coord.pen_pressure);
- input_report_key(dev, BTN_TOUCH, coord.tsw);
- input_sync(dev);
+ report_pen_events(w8001, &coord);
break;
- case 10:
+ /* control packet */
+ case W8001_PKTLEN_TPCCTL - 1:
+ tmp = (w8001->data[0] & W8001_TOUCH_MASK);
+ if (tmp == W8001_TOUCH_BYTE)
+ break;
+
w8001->idx = 0;
memcpy(w8001->response, w8001->data, W8001_MAX_LENGTH);
w8001->response_type = W8001_QUERY_PACKET;
complete(&w8001->cmd_done);
break;
+
+ /* 2 finger touch packet */
+ case W8001_PKTLEN_TOUCH2FG - 1:
+ w8001->idx = 0;
+ parse_touch(w8001);
+ break;
}
return IRQ_HANDLED;
@@ -167,6 +299,38 @@ static int w8001_setup(struct w8001 *w8001)
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
+ error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
+ if (!error) {
+ struct w8001_touch_query touch;
+
+ parse_touchquery(w8001->response, &touch);
+
+ switch (touch.sensor_id) {
+ case 0:
+ case 2:
+ w8001->pktlen = W8001_PKTLEN_TOUCH93;
+ break;
+ case 1:
+ case 3:
+ case 4:
+ w8001->pktlen = W8001_PKTLEN_TOUCH9A;
+ break;
+ case 5:
+ w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
+
+ input_mt_create_slots(dev, 2);
+ input_set_abs_params(dev, ABS_MT_TRACKING_ID,
+ 0, MAX_TRACKING_ID, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_X,
+ 0, touch.x, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y,
+ 0, touch.y, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
+ 0, 0, 0, 0);
+ break;
+ }
+ }
+
return w8001_command(w8001, W8001_CMD_START, false);
}
@@ -208,6 +372,7 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
w8001->serio = serio;
w8001->id = serio->id.id;
w8001->dev = input_dev;
+ w8001->trkid[0] = w8001->trkid[1] = -1;
init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
@@ -221,6 +386,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_dev->keybit[BIT_WORD(BTN_TOOL_PEN)] |= BIT_MASK(BTN_TOOL_PEN);
+ input_dev->keybit[BIT_WORD(BTN_TOOL_RUBBER)] |= BIT_MASK(BTN_TOOL_RUBBER);
+ input_dev->keybit[BIT_WORD(BTN_STYLUS)] |= BIT_MASK(BTN_STYLUS);
+ input_dev->keybit[BIT_WORD(BTN_STYLUS2)] |= BIT_MASK(BTN_STYLUS2);
serio_set_drvdata(serio, w8001);
err = serio_open(serio, drv);
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index cbfef1ea7e30..6b75c9f660ae 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -125,6 +125,8 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
{
int power_adc = 0, auxval;
u16 power = 0;
+ int rc = 0;
+ int timeout = 0;
/* get codec */
mutex_lock(&wm->codec_mutex);
@@ -143,7 +145,9 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
/* Turn polling mode on to read AUX ADC */
wm->pen_probably_down = 1;
- wm->codec->poll_sample(wm, adcsel, &auxval);
+
+ while (rc != RC_VALID && timeout++ < 5)
+ rc = wm->codec->poll_sample(wm, adcsel, &auxval);
if (power_adc)
wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000);
@@ -152,8 +156,15 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
wm->pen_probably_down = 0;
+ if (timeout >= 5) {
+ dev_err(wm->dev,
+ "timeout reading auxadc %d, disabling digitiser\n",
+ adcsel);
+ wm->codec->dig_enable(wm, false);
+ }
+
mutex_unlock(&wm->codec_mutex);
- return auxval & 0xfff;
+ return (rc == RC_VALID ? auxval & 0xfff : -EBUSY);
}
EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
@@ -684,8 +695,7 @@ static int wm97xx_probe(struct device *dev)
touch_reg_err:
platform_device_put(wm->touch_dev);
touch_err:
- platform_device_unregister(wm->battery_dev);
- wm->battery_dev = NULL;
+ platform_device_del(wm->battery_dev);
batt_reg_err:
platform_device_put(wm->battery_dev);
batt_err:
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index 7961d59f5cac..c06b4d50a3dc 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -25,14 +25,56 @@
#define IR_KEYPRESS_TIMEOUT 250
/**
+ * ir_create_table() - initializes a scancode table
+ * @rc_tab: the ir_scancode_table to initialize
+ * @name: name to assign to the table
+ * @ir_type: ir type to assign to the new table
+ * @size: initial size of the table
+ * @return: zero on success or a negative error code
+ *
+ * This routine will initialize the ir_scancode_table and will allocate
+ * memory to hold at least the specified number elements.
+ */
+static int ir_create_table(struct ir_scancode_table *rc_tab,
+ const char *name, u64 ir_type, size_t size)
+{
+ rc_tab->name = name;
+ rc_tab->ir_type = ir_type;
+ rc_tab->alloc = roundup_pow_of_two(size * sizeof(struct ir_scancode));
+ rc_tab->size = rc_tab->alloc / sizeof(struct ir_scancode);
+ rc_tab->scan = kmalloc(rc_tab->alloc, GFP_KERNEL);
+ if (!rc_tab->scan)
+ return -ENOMEM;
+
+ IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_tab->size, rc_tab->alloc);
+ return 0;
+}
+
+/**
+ * ir_free_table() - frees memory allocated by a scancode table
+ * @rc_tab: the table whose mappings need to be freed
+ *
+ * This routine will free memory alloctaed for key mappings used by given
+ * scancode table.
+ */
+static void ir_free_table(struct ir_scancode_table *rc_tab)
+{
+ rc_tab->size = 0;
+ kfree(rc_tab->scan);
+ rc_tab->scan = NULL;
+}
+
+/**
* ir_resize_table() - resizes a scancode table if necessary
* @rc_tab: the ir_scancode_table to resize
+ * @gfp_flags: gfp flags to use when allocating memory
* @return: zero on success or a negative error code
*
* This routine will shrink the ir_scancode_table if it has lots of
* unused entries and grow it if it is full.
*/
-static int ir_resize_table(struct ir_scancode_table *rc_tab)
+static int ir_resize_table(struct ir_scancode_table *rc_tab, gfp_t gfp_flags)
{
unsigned int oldalloc = rc_tab->alloc;
unsigned int newalloc = oldalloc;
@@ -57,7 +99,7 @@ static int ir_resize_table(struct ir_scancode_table *rc_tab)
if (newalloc == oldalloc)
return 0;
- newscan = kmalloc(newalloc, GFP_ATOMIC);
+ newscan = kmalloc(newalloc, gfp_flags);
if (!newscan) {
IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
return -ENOMEM;
@@ -72,26 +114,78 @@ static int ir_resize_table(struct ir_scancode_table *rc_tab)
}
/**
- * ir_do_setkeycode() - internal function to set a keycode in the
- * scancode->keycode table
+ * ir_update_mapping() - set a keycode in the scancode->keycode table
* @dev: the struct input_dev device descriptor
- * @rc_tab: the struct ir_scancode_table to set the keycode in
- * @scancode: the scancode for the ir command
- * @keycode: the keycode for the ir command
- * @resize: whether the keytable may be shrunk
- * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
+ * @rc_tab: scancode table to be adjusted
+ * @index: index of the mapping that needs to be updated
+ * @keycode: the desired keycode
+ * @return: previous keycode assigned to the mapping
+ *
+ * This routine is used to update scancode->keycopde mapping at given
+ * position.
+ */
+static unsigned int ir_update_mapping(struct input_dev *dev,
+ struct ir_scancode_table *rc_tab,
+ unsigned int index,
+ unsigned int new_keycode)
+{
+ int old_keycode = rc_tab->scan[index].keycode;
+ int i;
+
+ /* Did the user wish to remove the mapping? */
+ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
+ IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
+ index, rc_tab->scan[index].scancode);
+ rc_tab->len--;
+ memmove(&rc_tab->scan[index], &rc_tab->scan[index+ 1],
+ (rc_tab->len - index) * sizeof(struct ir_scancode));
+ } else {
+ IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
+ index,
+ old_keycode == KEY_RESERVED ? "New" : "Replacing",
+ rc_tab->scan[index].scancode, new_keycode);
+ rc_tab->scan[index].keycode = new_keycode;
+ __set_bit(new_keycode, dev->keybit);
+ }
+
+ if (old_keycode != KEY_RESERVED) {
+ /* A previous mapping was updated... */
+ __clear_bit(old_keycode, dev->keybit);
+ /* ... but another scancode might use the same keycode */
+ for (i = 0; i < rc_tab->len; i++) {
+ if (rc_tab->scan[i].keycode == old_keycode) {
+ __set_bit(old_keycode, dev->keybit);
+ break;
+ }
+ }
+
+ /* Possibly shrink the keytable, failure is not a problem */
+ ir_resize_table(rc_tab, GFP_ATOMIC);
+ }
+
+ return old_keycode;
+}
+
+/**
+ * ir_locate_scancode() - set a keycode in the scancode->keycode table
+ * @ir_dev: the struct ir_input_dev device descriptor
+ * @rc_tab: scancode table to be searched
+ * @scancode: the desired scancode
+ * @resize: controls whether we allowed to resize the table to
+ * accomodate not yet present scancodes
+ * @return: index of the mapping containing scancode in question
+ * or -1U in case of failure.
*
- * This routine is used internally to manipulate the scancode->keycode table.
- * The caller has to hold @rc_tab->lock.
+ * This routine is used to locate given scancode in ir_scancode_table.
+ * If scancode is not yet present the routine will allocate a new slot
+ * for it.
*/
-static int ir_do_setkeycode(struct input_dev *dev,
- struct ir_scancode_table *rc_tab,
- unsigned scancode, unsigned keycode,
- bool resize)
+static unsigned int ir_establish_scancode(struct ir_input_dev *ir_dev,
+ struct ir_scancode_table *rc_tab,
+ unsigned int scancode,
+ bool resize)
{
unsigned int i;
- int old_keycode = KEY_RESERVED;
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
/*
* Unfortunately, some hardware-based IR decoders don't provide
@@ -100,65 +194,34 @@ static int ir_do_setkeycode(struct input_dev *dev,
* the provided IR with another one, it is needed to allow loading
* IR tables from other remotes. So,
*/
- if (ir_dev->props && ir_dev->props->scanmask) {
+ if (ir_dev->props && ir_dev->props->scanmask)
scancode &= ir_dev->props->scanmask;
- }
/* First check if we already have a mapping for this ir command */
for (i = 0; i < rc_tab->len; i++) {
+ if (rc_tab->scan[i].scancode == scancode)
+ return i;
+
/* Keytable is sorted from lowest to highest scancode */
- if (rc_tab->scan[i].scancode > scancode)
+ if (rc_tab->scan[i].scancode >= scancode)
break;
- else if (rc_tab->scan[i].scancode < scancode)
- continue;
-
- old_keycode = rc_tab->scan[i].keycode;
- rc_tab->scan[i].keycode = keycode;
-
- /* Did the user wish to remove the mapping? */
- if (keycode == KEY_RESERVED || keycode == KEY_UNKNOWN) {
- IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
- i, scancode);
- rc_tab->len--;
- memmove(&rc_tab->scan[i], &rc_tab->scan[i + 1],
- (rc_tab->len - i) * sizeof(struct ir_scancode));
- }
-
- /* Possibly shrink the keytable, failure is not a problem */
- ir_resize_table(rc_tab);
- break;
}
- if (old_keycode == KEY_RESERVED && keycode != KEY_RESERVED) {
- /* No previous mapping found, we might need to grow the table */
- if (resize && ir_resize_table(rc_tab))
- return -ENOMEM;
-
- IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n",
- i, scancode, keycode);
+ /* No previous mapping found, we might need to grow the table */
+ if (rc_tab->size == rc_tab->len) {
+ if (!resize || ir_resize_table(rc_tab, GFP_ATOMIC))
+ return -1U;
+ }
- /* i is the proper index to insert our new keycode */
+ /* i is the proper index to insert our new keycode */
+ if (i < rc_tab->len)
memmove(&rc_tab->scan[i + 1], &rc_tab->scan[i],
(rc_tab->len - i) * sizeof(struct ir_scancode));
- rc_tab->scan[i].scancode = scancode;
- rc_tab->scan[i].keycode = keycode;
- rc_tab->len++;
- set_bit(keycode, dev->keybit);
- } else {
- IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
- i, scancode, keycode);
- /* A previous mapping was updated... */
- clear_bit(old_keycode, dev->keybit);
- /* ...but another scancode might use the same keycode */
- for (i = 0; i < rc_tab->len; i++) {
- if (rc_tab->scan[i].keycode == old_keycode) {
- set_bit(old_keycode, dev->keybit);
- break;
- }
- }
- }
+ rc_tab->scan[i].scancode = scancode;
+ rc_tab->scan[i].keycode = KEY_RESERVED;
+ rc_tab->len++;
- return 0;
+ return i;
}
/**
@@ -171,17 +234,41 @@ static int ir_do_setkeycode(struct input_dev *dev,
* This routine is used to handle evdev EVIOCSKEY ioctl.
*/
static int ir_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
- int rc;
- unsigned long flags;
struct ir_input_dev *ir_dev = input_get_drvdata(dev);
struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
+ unsigned int index;
+ unsigned int scancode;
+ int retval;
+ unsigned long flags;
spin_lock_irqsave(&rc_tab->lock, flags);
- rc = ir_do_setkeycode(dev, rc_tab, scancode, keycode, true);
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ if (index >= rc_tab->len) {
+ retval = -EINVAL;
+ goto out;
+ }
+ } else {
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ index = ir_establish_scancode(ir_dev, rc_tab, scancode, true);
+ if (index >= rc_tab->len) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ }
+
+ *old_keycode = ir_update_mapping(dev, rc_tab, index, ke->keycode);
+
+out:
spin_unlock_irqrestore(&rc_tab->lock, flags);
- return rc;
+ return retval;
}
/**
@@ -189,32 +276,73 @@ static int ir_setkeycode(struct input_dev *dev,
* @dev: the struct input_dev device descriptor
* @to: the struct ir_scancode_table to copy entries to
* @from: the struct ir_scancode_table to copy entries from
- * @return: -EINVAL if all keycodes could not be inserted, otherwise zero.
+ * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero.
*
* This routine is used to handle table initialization.
*/
-static int ir_setkeytable(struct input_dev *dev,
- struct ir_scancode_table *to,
+static int ir_setkeytable(struct ir_input_dev *ir_dev,
const struct ir_scancode_table *from)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
- unsigned long flags;
- unsigned int i;
- int rc = 0;
+ unsigned int i, index;
+ int rc;
+
+ rc = ir_create_table(&ir_dev->rc_tab,
+ from->name, from->ir_type, from->size);
+ if (rc)
+ return rc;
+
+ IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_tab->size, rc_tab->alloc);
- spin_lock_irqsave(&rc_tab->lock, flags);
for (i = 0; i < from->size; i++) {
- rc = ir_do_setkeycode(dev, to, from->scan[i].scancode,
- from->scan[i].keycode, false);
- if (rc)
+ index = ir_establish_scancode(ir_dev, rc_tab,
+ from->scan[i].scancode, false);
+ if (index >= rc_tab->len) {
+ rc = -ENOMEM;
break;
+ }
+
+ ir_update_mapping(ir_dev->input_dev, rc_tab, index,
+ from->scan[i].keycode);
}
- spin_unlock_irqrestore(&rc_tab->lock, flags);
+
+ if (rc)
+ ir_free_table(rc_tab);
+
return rc;
}
/**
+ * ir_lookup_by_scancode() - locate mapping by scancode
+ * @rc_tab: the &struct ir_scancode_table to search
+ * @scancode: scancode to look for in the table
+ * @return: index in the table, -1U if not found
+ *
+ * This routine performs binary search in RC keykeymap table for
+ * given scancode.
+ */
+static unsigned int ir_lookup_by_scancode(const struct ir_scancode_table *rc_tab,
+ unsigned int scancode)
+{
+ unsigned int start = 0;
+ unsigned int end = rc_tab->len - 1;
+ unsigned int mid;
+
+ while (start <= end) {
+ mid = (start + end) / 2;
+ if (rc_tab->scan[mid].scancode < scancode)
+ start = mid + 1;
+ else if (rc_tab->scan[mid].scancode > scancode)
+ end = mid - 1;
+ else
+ return mid;
+ }
+
+ return -1U;
+}
+
+/**
* ir_getkeycode() - get a keycode from the scancode->keycode table
* @dev: the struct input_dev device descriptor
* @scancode: the desired scancode
@@ -224,36 +352,46 @@ static int ir_setkeytable(struct input_dev *dev,
* This routine is used to handle evdev EVIOCGKEY ioctl.
*/
static int ir_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
+ struct input_keymap_entry *ke)
{
- int start, end, mid;
- unsigned long flags;
- int key = KEY_RESERVED;
struct ir_input_dev *ir_dev = input_get_drvdata(dev);
struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
+ struct ir_scancode *entry;
+ unsigned long flags;
+ unsigned int index;
+ unsigned int scancode;
+ int retval;
spin_lock_irqsave(&rc_tab->lock, flags);
- start = 0;
- end = rc_tab->len - 1;
- while (start <= end) {
- mid = (start + end) / 2;
- if (rc_tab->scan[mid].scancode < scancode)
- start = mid + 1;
- else if (rc_tab->scan[mid].scancode > scancode)
- end = mid - 1;
- else {
- key = rc_tab->scan[mid].keycode;
- break;
- }
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ } else {
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ index = ir_lookup_by_scancode(rc_tab, scancode);
+ }
+
+ if (index >= rc_tab->len) {
+ if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
+ IR_dprintk(1, "unknown key for scancode 0x%04x\n",
+ scancode);
+ retval = -EINVAL;
+ goto out;
}
- spin_unlock_irqrestore(&rc_tab->lock, flags);
- if (key == KEY_RESERVED)
- IR_dprintk(1, "unknown key for scancode 0x%04x\n",
- scancode);
+ entry = &rc_tab->scan[index];
- *keycode = key;
- return 0;
+ ke->index = index;
+ ke->keycode = entry->keycode;
+ ke->len = sizeof(entry->scancode);
+ memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
+
+out:
+ spin_unlock_irqrestore(&rc_tab->lock, flags);
+ return retval;
}
/**
@@ -268,12 +406,24 @@ static int ir_getkeycode(struct input_dev *dev,
*/
u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
{
- int keycode;
+ struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+ struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
+ unsigned int keycode;
+ unsigned int index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc_tab->lock, flags);
+
+ index = ir_lookup_by_scancode(rc_tab, scancode);
+ keycode = index < rc_tab->len ?
+ rc_tab->scan[index].keycode : KEY_RESERVED;
+
+ spin_unlock_irqrestore(&rc_tab->lock, flags);
- ir_getkeycode(dev, scancode, &keycode);
if (keycode != KEY_RESERVED)
IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
dev->name, scancode, keycode);
+
return keycode;
}
EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
@@ -453,8 +603,8 @@ int __ir_input_register(struct input_dev *input_dev,
goto out_dev;
}
- input_dev->getkeycode = ir_getkeycode;
- input_dev->setkeycode = ir_setkeycode;
+ input_dev->getkeycode_new = ir_getkeycode;
+ input_dev->setkeycode_new = ir_setkeycode;
input_set_drvdata(input_dev, ir_dev);
ir_dev->input_dev = input_dev;
@@ -462,12 +612,6 @@ int __ir_input_register(struct input_dev *input_dev,
spin_lock_init(&ir_dev->keylock);
setup_timer(&ir_dev->timer_keyup, ir_timer_keyup, (unsigned long)ir_dev);
- ir_dev->rc_tab.name = rc_tab->name;
- ir_dev->rc_tab.ir_type = rc_tab->ir_type;
- ir_dev->rc_tab.alloc = roundup_pow_of_two(rc_tab->size *
- sizeof(struct ir_scancode));
- ir_dev->rc_tab.scan = kmalloc(ir_dev->rc_tab.alloc, GFP_KERNEL);
- ir_dev->rc_tab.size = ir_dev->rc_tab.alloc / sizeof(struct ir_scancode);
if (props) {
ir_dev->props = props;
if (props->open)
@@ -476,23 +620,14 @@ int __ir_input_register(struct input_dev *input_dev,
input_dev->close = ir_close;
}
- if (!ir_dev->rc_tab.scan) {
- rc = -ENOMEM;
- goto out_name;
- }
-
- IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
- ir_dev->rc_tab.size, ir_dev->rc_tab.alloc);
-
set_bit(EV_KEY, input_dev->evbit);
set_bit(EV_REP, input_dev->evbit);
set_bit(EV_MSC, input_dev->evbit);
set_bit(MSC_SCAN, input_dev->mscbit);
- if (ir_setkeytable(input_dev, &ir_dev->rc_tab, rc_tab)) {
- rc = -ENOMEM;
- goto out_table;
- }
+ rc = ir_setkeytable(ir_dev, rc_tab);
+ if (rc)
+ goto out_name;
rc = ir_register_class(input_dev);
if (rc < 0)
@@ -522,7 +657,7 @@ int __ir_input_register(struct input_dev *input_dev,
out_event:
ir_unregister_class(input_dev);
out_table:
- kfree(ir_dev->rc_tab.scan);
+ ir_free_table(&ir_dev->rc_tab);
out_name:
kfree(ir_dev->driver_name);
out_dev:
@@ -540,7 +675,6 @@ EXPORT_SYMBOL_GPL(__ir_input_register);
void ir_input_unregister(struct input_dev *input_dev)
{
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct ir_scancode_table *rc_tab;
if (!ir_dev)
return;
@@ -552,10 +686,7 @@ void ir_input_unregister(struct input_dev *input_dev)
if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
ir_raw_event_unregister(input_dev);
- rc_tab = &ir_dev->rc_tab;
- rc_tab->size = 0;
- kfree(rc_tab->scan);
- rc_tab->scan = NULL;
+ ir_free_table(&ir_dev->rc_tab);
ir_unregister_class(input_dev);
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index defa786dee34..b8c4b80e4c43 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -338,6 +338,21 @@ static struct resource ab8500_rtc_resources[] = {
},
};
+static struct resource ab8500_poweronkey_db_resources[] = {
+ {
+ .name = "ONKEY_DBF",
+ .start = AB8500_INT_PON_KEY1DB_F,
+ .end = AB8500_INT_PON_KEY1DB_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ONKEY_DBR",
+ .start = AB8500_INT_PON_KEY1DB_R,
+ .end = AB8500_INT_PON_KEY1DB_R,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct mfd_cell ab8500_devs[] = {
{
.name = "ab8500-gpadc",
@@ -354,6 +369,11 @@ static struct mfd_cell ab8500_devs[] = {
{ .name = "ab8500-usb", },
{ .name = "ab8500-pwm", },
{ .name = "ab8500-regulator", },
+ {
+ .name = "ab8500-poweron-key",
+ .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+ .resources = ab8500_poweronkey_db_resources,
+ },
};
int __devinit ab8500_init(struct ab8500 *ab8500)
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c
index cd164595f08a..49b4d069cbf9 100644
--- a/drivers/mfd/sh_mobile_sdhi.c
+++ b/drivers/mfd/sh_mobile_sdhi.c
@@ -65,7 +65,7 @@ static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state)
p->set_pwr(pdev, state);
}
-static int __init sh_mobile_sdhi_probe(struct platform_device *pdev)
+static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
{
struct sh_mobile_sdhi *priv;
struct tmio_mmc_data *mmc_data;
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 6f512b5c117b..ea22520c0406 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -924,6 +924,13 @@ static int __devinit m25p_probe(struct spi_device *spi)
nr_parts = data->nr_parts;
}
+#ifdef CONFIG_OF
+ if (nr_parts <= 0 && spi->dev.of_node) {
+ nr_parts = of_mtd_parse_partitions(&spi->dev,
+ spi->dev.of_node, &parts);
+ }
+#endif
+
if (nr_parts > 0) {
for (i = 0; i < nr_parts; i++) {
DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index fe63f6bd663c..ec3edf6e68b4 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -294,7 +294,7 @@ static int __devinit of_flash_probe(struct platform_device *dev,
info->list[i].map.name = dev_name(&dev->dev);
info->list[i].map.phys = res.start;
info->list[i].map.size = res_size;
- info->list[i].map.bankwidth = *width;
+ info->list[i].map.bankwidth = be32_to_cpup(width);
err = -ENOMEM;
info->list[i].map.virt = ioremap(info->list[i].map.phys,
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index 8bf7dc6d1ce6..7bd171eefd21 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -53,8 +53,8 @@ int __devinit of_mtd_parse_partitions(struct device *dev,
continue;
}
- (*pparts)[i].offset = reg[0];
- (*pparts)[i].size = reg[1];
+ (*pparts)[i].offset = be32_to_cpu(reg[0]);
+ (*pparts)[i].size = be32_to_cpu(reg[1]);
partname = of_get_property(pp, "label", &len);
if (!partname)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 6acbff389ab6..aa675ebd8eb3 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -4,7 +4,7 @@ config DTC
config OF
bool
-menu "Flattened Device Tree and Open Firmware support"
+menu "Device Tree and Open Firmware support"
depends on OF
config PROC_DEVICETREE
@@ -19,6 +19,9 @@ config OF_FLATTREE
bool
select DTC
+config OF_PROMTREE
+ bool
+
config OF_DYNAMIC
def_bool y
depends on PPC_OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 0052c405463a..7888155bea08 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,5 +1,6 @@
obj-y = base.o
obj-$(CONFIG_OF_FLATTREE) += fdt.o
+obj-$(CONFIG_OF_PROMTREE) += pdt.o
obj-$(CONFIG_OF_ADDRESS) += address.o
obj-$(CONFIG_OF_IRQ) += irq.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o
diff --git a/drivers/of/address.c b/drivers/of/address.c
index fcadb726d4f9..3a1c7e70b192 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -163,7 +163,7 @@ static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
unsigned int *flags)
{
- const u32 *prop;
+ const __be32 *prop;
unsigned int psize;
struct device_node *parent;
struct of_bus *bus;
diff --git a/drivers/of/base.c b/drivers/of/base.c
index aa805250de76..710b53bfac6d 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -33,7 +33,7 @@ DEFINE_RWLOCK(devtree_lock);
int of_n_addr_cells(struct device_node *np)
{
- const int *ip;
+ const __be32 *ip;
do {
if (np->parent)
@@ -49,7 +49,7 @@ EXPORT_SYMBOL(of_n_addr_cells);
int of_n_size_cells(struct device_node *np)
{
- const int *ip;
+ const __be32 *ip;
do {
if (np->parent)
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 92de0eb74aea..45d86530799f 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -81,29 +81,10 @@ struct device_attribute of_platform_device_attrs[] = {
__ATTR_NULL
};
-/**
- * of_release_dev - free an of 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 of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
- struct platform_device *ofdev;
-
- ofdev = to_platform_device(dev);
- of_node_put(ofdev->dev.of_node);
- kfree(ofdev);
-}
-EXPORT_SYMBOL(of_release_dev);
-
-int of_device_register(struct platform_device *ofdev)
+int of_device_add(struct platform_device *ofdev)
{
BUG_ON(ofdev->dev.of_node == NULL);
- device_initialize(&ofdev->dev);
-
/* name and id have to be set so that the platform bus doesn't get
* confused on matching */
ofdev->name = dev_name(&ofdev->dev);
@@ -117,6 +98,12 @@ int of_device_register(struct platform_device *ofdev)
return device_add(&ofdev->dev);
}
+
+int of_device_register(struct platform_device *pdev)
+{
+ device_initialize(&pdev->dev);
+ return of_device_add(pdev);
+}
EXPORT_SYMBOL(of_device_register);
void of_device_unregister(struct platform_device *ofdev)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 65da5aec7552..c1360e02f921 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -533,8 +533,6 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#endif /* CONFIG_CMDLINE */
- early_init_dt_scan_chosen_arch(node);
-
pr_debug("Command line is: %s\n", cmd_line);
/* break now */
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 6e595e5a3977..75b0d3cb7676 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -24,6 +24,11 @@
#include <linux/of_irq.h>
#include <linux/string.h>
+/* For archs that don't support NO_IRQ (such as x86), provide a dummy value */
+#ifndef NO_IRQ
+#define NO_IRQ 0
+#endif
+
/**
* irq_of_parse_and_map - Parse and map an interrupt into linux virq space
* @device: Device node of the device whose interrupt is to be mapped
@@ -347,3 +352,37 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
return irq;
}
EXPORT_SYMBOL_GPL(of_irq_to_resource);
+
+/**
+ * of_irq_count - Count the number of IRQs a node uses
+ * @dev: pointer to device tree node
+ */
+int of_irq_count(struct device_node *dev)
+{
+ int nr = 0;
+
+ while (of_irq_to_resource(dev, nr, NULL) != NO_IRQ)
+ nr++;
+
+ return nr;
+}
+
+/**
+ * of_irq_to_resource_table - Fill in resource table with node's IRQ info
+ * @dev: pointer to device tree node
+ * @res: array of resources to fill in
+ * @nr_irqs: the number of IRQs (and upper bound for num of @res elements)
+ *
+ * Returns the size of the filled in table (up to @nr_irqs).
+ */
+int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
+ int nr_irqs)
+{
+ int i;
+
+ for (i = 0; i < nr_irqs; i++, res++)
+ if (of_irq_to_resource(dev, i, res) == NO_IRQ)
+ break;
+
+ return i;
+}
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index 0a694debd226..c85d3c7421fc 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -12,6 +12,7 @@
*/
#include <linux/i2c.h>
+#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_i2c.h>
#include <linux/of_irq.h>
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c
new file mode 100644
index 000000000000..28295d0a50f6
--- /dev/null
+++ b/drivers/of/pdt.c
@@ -0,0 +1,276 @@
+/* pdt.c: OF PROM device tree support code.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc by David S. Miller davem@davemloft.net
+ * Adapted for multiple architectures by Andres Salomon <dilinger@queued.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_pdt.h>
+#include <asm/prom.h>
+
+static struct of_pdt_ops *of_pdt_prom_ops __initdata;
+
+void __initdata (*of_pdt_build_more)(struct device_node *dp,
+ struct device_node ***nextp);
+
+#if defined(CONFIG_SPARC)
+unsigned int of_pdt_unique_id __initdata;
+
+#define of_pdt_incr_unique_id(p) do { \
+ (p)->unique_id = of_pdt_unique_id++; \
+} while (0)
+
+static inline const char *of_pdt_node_name(struct device_node *dp)
+{
+ return dp->path_component_name;
+}
+
+#else
+
+static inline void of_pdt_incr_unique_id(void *p) { }
+static inline void irq_trans_init(struct device_node *dp) { }
+
+static inline const char *of_pdt_node_name(struct device_node *dp)
+{
+ return dp->name;
+}
+
+#endif /* !CONFIG_SPARC */
+
+static struct property * __init of_pdt_build_one_prop(phandle node, char *prev,
+ char *special_name,
+ void *special_val,
+ int special_len)
+{
+ static struct property *tmp = NULL;
+ struct property *p;
+ int err;
+
+ if (tmp) {
+ p = tmp;
+ memset(p, 0, sizeof(*p) + 32);
+ tmp = NULL;
+ } else {
+ p = prom_early_alloc(sizeof(struct property) + 32);
+ of_pdt_incr_unique_id(p);
+ }
+
+ p->name = (char *) (p + 1);
+ if (special_name) {
+ strcpy(p->name, special_name);
+ p->length = special_len;
+ p->value = prom_early_alloc(special_len);
+ memcpy(p->value, special_val, special_len);
+ } else {
+ err = of_pdt_prom_ops->nextprop(node, prev, p->name);
+ if (err) {
+ tmp = p;
+ return NULL;
+ }
+ p->length = of_pdt_prom_ops->getproplen(node, p->name);
+ if (p->length <= 0) {
+ p->length = 0;
+ } else {
+ int len;
+
+ p->value = prom_early_alloc(p->length + 1);
+ len = of_pdt_prom_ops->getproperty(node, p->name,
+ p->value, p->length);
+ if (len <= 0)
+ p->length = 0;
+ ((unsigned char *)p->value)[p->length] = '\0';
+ }
+ }
+ return p;
+}
+
+static struct property * __init of_pdt_build_prop_list(phandle node)
+{
+ struct property *head, *tail;
+
+ head = tail = of_pdt_build_one_prop(node, NULL,
+ ".node", &node, sizeof(node));
+
+ tail->next = of_pdt_build_one_prop(node, NULL, NULL, NULL, 0);
+ tail = tail->next;
+ while(tail) {
+ tail->next = of_pdt_build_one_prop(node, tail->name,
+ NULL, NULL, 0);
+ tail = tail->next;
+ }
+
+ return head;
+}
+
+static char * __init of_pdt_get_one_property(phandle node, const char *name)
+{
+ char *buf = "<NULL>";
+ int len;
+
+ len = of_pdt_prom_ops->getproplen(node, name);
+ if (len > 0) {
+ buf = prom_early_alloc(len);
+ len = of_pdt_prom_ops->getproperty(node, name, buf, len);
+ }
+
+ return buf;
+}
+
+static char * __init of_pdt_try_pkg2path(phandle node)
+{
+ char *res, *buf = NULL;
+ int len;
+
+ if (!of_pdt_prom_ops->pkg2path)
+ return NULL;
+
+ if (of_pdt_prom_ops->pkg2path(node, buf, 0, &len))
+ return NULL;
+ buf = prom_early_alloc(len + 1);
+ if (of_pdt_prom_ops->pkg2path(node, buf, len, &len)) {
+ pr_err("%s: package-to-path failed\n", __func__);
+ return NULL;
+ }
+
+ res = strrchr(buf, '/');
+ if (!res) {
+ pr_err("%s: couldn't find / in %s\n", __func__, buf);
+ return NULL;
+ }
+ return res+1;
+}
+
+/*
+ * When fetching the node's name, first try using package-to-path; if
+ * that fails (either because the arch hasn't supplied a PROM callback,
+ * or some other random failure), fall back to just looking at the node's
+ * 'name' property.
+ */
+static char * __init of_pdt_build_name(phandle node)
+{
+ char *buf;
+
+ buf = of_pdt_try_pkg2path(node);
+ if (!buf)
+ buf = of_pdt_get_one_property(node, "name");
+
+ return buf;
+}
+
+static struct device_node * __init of_pdt_create_node(phandle node,
+ struct device_node *parent)
+{
+ struct device_node *dp;
+
+ if (!node)
+ return NULL;
+
+ dp = prom_early_alloc(sizeof(*dp));
+ of_pdt_incr_unique_id(dp);
+ dp->parent = parent;
+
+ kref_init(&dp->kref);
+
+ dp->name = of_pdt_build_name(node);
+ dp->type = of_pdt_get_one_property(node, "device_type");
+ dp->phandle = node;
+
+ dp->properties = of_pdt_build_prop_list(node);
+
+ irq_trans_init(dp);
+
+ return dp;
+}
+
+static char * __init of_pdt_build_full_name(struct device_node *dp)
+{
+ int len, ourlen, plen;
+ char *n;
+
+ plen = strlen(dp->parent->full_name);
+ ourlen = strlen(of_pdt_node_name(dp));
+ len = ourlen + plen + 2;
+
+ n = prom_early_alloc(len);
+ strcpy(n, dp->parent->full_name);
+ if (!of_node_is_root(dp->parent)) {
+ strcpy(n + plen, "/");
+ plen++;
+ }
+ strcpy(n + plen, of_pdt_node_name(dp));
+
+ return n;
+}
+
+static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
+ phandle node,
+ struct device_node ***nextp)
+{
+ struct device_node *ret = NULL, *prev_sibling = NULL;
+ struct device_node *dp;
+
+ while (1) {
+ dp = of_pdt_create_node(node, parent);
+ if (!dp)
+ break;
+
+ if (prev_sibling)
+ prev_sibling->sibling = dp;
+
+ if (!ret)
+ ret = dp;
+ prev_sibling = dp;
+
+ *(*nextp) = dp;
+ *nextp = &dp->allnext;
+
+#if defined(CONFIG_SPARC)
+ dp->path_component_name = build_path_component(dp);
+#endif
+ dp->full_name = of_pdt_build_full_name(dp);
+
+ dp->child = of_pdt_build_tree(dp,
+ of_pdt_prom_ops->getchild(node), nextp);
+
+ if (of_pdt_build_more)
+ of_pdt_build_more(dp, nextp);
+
+ node = of_pdt_prom_ops->getsibling(node);
+ }
+
+ return ret;
+}
+
+void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
+{
+ struct device_node **nextp;
+
+ BUG_ON(!ops);
+ of_pdt_prom_ops = ops;
+
+ allnodes = of_pdt_create_node(root_node, NULL);
+#if defined(CONFIG_SPARC)
+ allnodes->path_component_name = "";
+#endif
+ allnodes->full_name = "/";
+
+ nextp = &allnodes->allnext;
+ allnodes->child = of_pdt_build_tree(allnodes,
+ of_pdt_prom_ops->getchild(allnodes->phandle), &nextp);
+}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index bb72223c22ae..5b4a07f1220e 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -584,34 +584,33 @@ struct platform_device *of_device_alloc(struct device_node *np,
struct device *parent)
{
struct platform_device *dev;
- int rc, i, num_reg = 0, num_irq = 0;
+ int rc, i, num_reg = 0, num_irq;
struct resource *res, temp_res;
- /* First count how many resources are needed */
- while (of_address_to_resource(np, num_reg, &temp_res) == 0)
- num_reg++;
- while (of_irq_to_resource(np, num_irq, &temp_res) != NO_IRQ)
- num_irq++;
-
- /* Allocate memory for both the struct device and the resource table */
- dev = kzalloc(sizeof(*dev) + (sizeof(*res) * (num_reg + num_irq)),
- GFP_KERNEL);
+ dev = platform_device_alloc("", -1);
if (!dev)
return NULL;
- res = (struct resource *) &dev[1];
+
+ /* count the io and irq resources */
+ while (of_address_to_resource(np, num_reg, &temp_res) == 0)
+ num_reg++;
+ num_irq = of_irq_count(np);
/* Populate the resource table */
if (num_irq || num_reg) {
+ res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
+ if (!res) {
+ platform_device_put(dev);
+ return NULL;
+ }
+
dev->num_resources = num_reg + num_irq;
dev->resource = res;
for (i = 0; i < num_reg; i++, res++) {
rc = of_address_to_resource(np, i, res);
WARN_ON(rc);
}
- for (i = 0; i < num_irq; i++, res++) {
- rc = of_irq_to_resource(np, i, res);
- WARN_ON(rc == NO_IRQ);
- }
+ WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
}
dev->dev.of_node = of_node_get(np);
@@ -619,7 +618,6 @@ struct platform_device *of_device_alloc(struct device_node *np,
dev->dev.dma_mask = &dev->archdata.dma_mask;
#endif
dev->dev.parent = parent;
- dev->dev.release = of_release_dev;
if (bus_id)
dev_set_name(&dev->dev, "%s", bus_id);
@@ -657,8 +655,8 @@ struct platform_device *of_platform_device_create(struct device_node *np,
* to do such, possibly using a device notifier
*/
- if (of_device_register(dev) != 0) {
- of_device_free(dev);
+ if (of_device_add(dev) != 0) {
+ platform_device_put(dev);
return NULL;
}
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cff7cc2c1f02..faec777b1ed4 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -92,6 +92,7 @@ config DELL_WMI
tristate "Dell WMI extras"
depends on ACPI_WMI
depends on INPUT
+ select INPUT_SPARSEKMAP
---help---
Say Y here if you want to support WMI-based hotkeys on Dell laptops.
@@ -140,6 +141,7 @@ config HP_WMI
depends on ACPI_WMI
depends on INPUT
depends on RFKILL || RFKILL = n
+ select INPUT_SPARSEKMAP
help
Say Y here if you want to support WMI-based hotkeys on HP laptops and
to read data from WMI such as docking or ambient light sensor state.
@@ -171,6 +173,7 @@ config PANASONIC_LAPTOP
tristate "Panasonic Laptop Extras"
depends on INPUT && ACPI
depends on BACKLIGHT_CLASS_DEVICE
+ select INPUT_SPARSEKMAP
---help---
This driver adds support for access to backlight control and hotkeys
on Panasonic Let's Note laptops.
@@ -219,8 +222,8 @@ config SONYPI_COMPAT
---help---
Build the sonypi driver compatibility code into the sony-laptop driver.
-config IDEAPAD_ACPI
- tristate "Lenovo IdeaPad ACPI Laptop Extras"
+config IDEAPAD_LAPTOP
+ tristate "Lenovo IdeaPad Laptop Extras"
depends on ACPI
depends on RFKILL
help
@@ -365,6 +368,26 @@ config THINKPAD_ACPI_HOTKEY_POLL
If you are not sure, say Y here. The driver enables polling only if
it is strictly necessary to do so.
+config SENSORS_HDAPS
+ tristate "Thinkpad Hard Drive Active Protection System (hdaps)"
+ depends on INPUT && X86
+ select INPUT_POLLDEV
+ default n
+ help
+ This driver provides support for the IBM Hard Drive Active Protection
+ System (hdaps), which provides an accelerometer and other misc. data.
+ ThinkPads starting with the R50, T41, and X40 are supported. The
+ accelerometer data is readable via sysfs.
+
+ This driver also provides an absolute input class device, allowing
+ the laptop to act as a pinball machine-esque joystick.
+
+ If your ThinkPad is not recognized by the driver, please update to latest
+ BIOS. This is especially the case for some R52 ThinkPads.
+
+ Say Y here if you have an applicable laptop and want to experience
+ the awesome power of hdaps.
+
config INTEL_MENLOW
tristate "Thermal Management driver for Intel menlow platform"
depends on ACPI_THERMAL
@@ -478,6 +501,7 @@ config TOPSTAR_LAPTOP
tristate "Topstar Laptop Extras"
depends on ACPI
depends on INPUT
+ select INPUT_SPARSEKMAP
---help---
This driver adds support for hotkeys found on Topstar laptops.
@@ -492,6 +516,7 @@ config ACPI_TOSHIBA
depends on INPUT
depends on RFKILL || RFKILL = n
select INPUT_POLLDEV
+ select INPUT_SPARSEKMAP
---help---
This driver adds support for access to certain system settings
on "legacy free" Toshiba laptops. These laptops can be recognized by
@@ -590,4 +615,28 @@ config INTEL_IPS
functionality. If in doubt, say Y here; it will only load on
supported platforms.
+config IBM_RTL
+ tristate "Device driver to enable PRTL support"
+ depends on X86 && PCI
+ ---help---
+ Enable support for IBM Premium Real Time Mode (PRTM).
+ This module will allow you the enter and exit PRTM in the BIOS via
+ sysfs on platforms that support this feature. System in PRTM will
+ not receive CPU-generated SMIs for recoverable errors. Use of this
+ feature without proper support may void your hardware warranty.
+
+ If the proper BIOS support is found the driver will load and create
+ /sys/devices/system/ibm_rtl/. The "state" variable will indicate
+ whether or not the BIOS is in PRTM.
+ state = 0 (BIOS SMIs on)
+ state = 1 (BIOS SMIs off)
+
+config XO1_RFKILL
+ tristate "OLPC XO-1 software RF kill switch"
+ depends on OLPC
+ depends on RFKILL
+ ---help---
+ Support for enabling/disabling the WLAN interface on the OLPC XO-1
+ laptop.
+
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 85fb2b84f57e..9950ccc940b5 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -15,8 +15,9 @@ obj-$(CONFIG_ACERHDF) += acerhdf.o
obj-$(CONFIG_HP_WMI) += hp-wmi.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
-obj-$(CONFIG_IDEAPAD_ACPI) += ideapad_acpi.o
+obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
+obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
@@ -30,4 +31,5 @@ obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
-
+obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o
+obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 2badee2fdeed..c8c65375bfe2 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -1314,7 +1314,7 @@ static int __init acer_wmi_init(void)
AMW0_find_mailled();
if (!interface) {
- printk(ACER_ERR "No or unsupported WMI interface, unable to "
+ printk(ACER_INFO "No or unsupported WMI interface, unable to "
"load\n");
return -ENODEV;
}
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b756e07d41b4..60a5a5c6b50a 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -236,7 +236,6 @@ struct asus_laptop {
u8 light_level; /* light sensor level */
u8 light_switch; /* light sensor switch value */
u16 event_count[128]; /* count for each event TODO make this better */
- u16 *keycode_map;
};
static const struct key_entry asus_keymap[] = {
@@ -278,6 +277,7 @@ static const struct key_entry asus_keymap[] = {
{KE_KEY, 0x99, { KEY_PHONE } },
{KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
{KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
+ {KE_KEY, 0xb5, { KEY_CALC } },
{KE_END, 0},
};
@@ -639,29 +639,29 @@ static int asus_backlight_notify(struct asus_laptop *asus)
static int asus_backlight_init(struct asus_laptop *asus)
{
struct backlight_device *bd;
- struct device *dev = &asus->platform_device->dev;
struct backlight_properties props;
- if (!acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) &&
- !acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) &&
- lcd_switch_handle) {
- memset(&props, 0, sizeof(struct backlight_properties));
- props.max_brightness = 15;
-
- bd = backlight_device_register(ASUS_LAPTOP_FILE, dev,
- asus, &asusbl_ops, &props);
- if (IS_ERR(bd)) {
- pr_err("Could not register asus backlight device\n");
- asus->backlight_device = NULL;
- return PTR_ERR(bd);
- }
+ if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) ||
+ acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) ||
+ !lcd_switch_handle)
+ return 0;
- asus->backlight_device = bd;
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = 15;
- bd->props.power = FB_BLANK_UNBLANK;
- bd->props.brightness = asus_read_brightness(bd);
- backlight_update_status(bd);
+ bd = backlight_device_register(ASUS_LAPTOP_FILE,
+ &asus->platform_device->dev, asus,
+ &asusbl_ops, &props);
+ if (IS_ERR(bd)) {
+ pr_err("Could not register asus backlight device\n");
+ asus->backlight_device = NULL;
+ return PTR_ERR(bd);
}
+
+ asus->backlight_device = bd;
+ bd->props.brightness = asus_read_brightness(bd);
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
return 0;
}
@@ -1065,9 +1065,9 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
*/
static int asus_gps_rfkill_set(void *data, bool blocked)
{
- acpi_handle handle = data;
+ struct asus_laptop *asus = data;
- return asus_gps_switch(handle, !blocked);
+ return asus_gps_switch(asus, !blocked);
}
static const struct rfkill_ops asus_gps_rfkill_ops = {
@@ -1094,7 +1094,7 @@ static int asus_rfkill_init(struct asus_laptop *asus)
asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
RFKILL_TYPE_GPS,
- &asus_gps_rfkill_ops, NULL);
+ &asus_gps_rfkill_ops, asus);
if (!asus->gps_rfkill)
return -EINVAL;
@@ -1130,7 +1130,6 @@ static int asus_input_init(struct asus_laptop *asus)
input->phys = ASUS_LAPTOP_FILE "/input0";
input->id.bustype = BUS_HOST;
input->dev.parent = &asus->platform_device->dev;
- input_set_drvdata(input, asus);
error = sparse_keymap_setup(input, asus_keymap, NULL);
if (error) {
@@ -1159,6 +1158,7 @@ static void asus_input_exit(struct asus_laptop *asus)
sparse_keymap_free(asus->inputdev);
input_unregister_device(asus->inputdev);
}
+ asus->inputdev = NULL;
}
/*
@@ -1200,111 +1200,100 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL);
static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan);
-static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, show_bluetooth,
- store_bluetooth);
+static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
+ show_bluetooth, store_bluetooth);
static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp);
static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
-static void asus_sysfs_exit(struct asus_laptop *asus)
-{
- struct platform_device *device = asus->platform_device;
-
- device_remove_file(&device->dev, &dev_attr_infos);
- device_remove_file(&device->dev, &dev_attr_wlan);
- device_remove_file(&device->dev, &dev_attr_bluetooth);
- device_remove_file(&device->dev, &dev_attr_display);
- device_remove_file(&device->dev, &dev_attr_ledd);
- device_remove_file(&device->dev, &dev_attr_ls_switch);
- device_remove_file(&device->dev, &dev_attr_ls_level);
- device_remove_file(&device->dev, &dev_attr_gps);
-}
+static struct attribute *asus_attributes[] = {
+ &dev_attr_infos.attr,
+ &dev_attr_wlan.attr,
+ &dev_attr_bluetooth.attr,
+ &dev_attr_display.attr,
+ &dev_attr_ledd.attr,
+ &dev_attr_ls_level.attr,
+ &dev_attr_ls_switch.attr,
+ &dev_attr_gps.attr,
+ NULL
+};
-static int asus_sysfs_init(struct asus_laptop *asus)
+static mode_t asus_sysfs_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int idx)
{
- struct platform_device *device = asus->platform_device;
- int err;
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct asus_laptop *asus = platform_get_drvdata(pdev);
+ acpi_handle handle = asus->handle;
+ bool supported;
- err = device_create_file(&device->dev, &dev_attr_infos);
- if (err)
- return err;
+ if (attr == &dev_attr_wlan.attr) {
+ supported = !acpi_check_handle(handle, METHOD_WLAN, NULL);
- if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_wlan);
- if (err)
- return err;
- }
+ } else if (attr == &dev_attr_bluetooth.attr) {
+ supported = !acpi_check_handle(handle, METHOD_BLUETOOTH, NULL);
- if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_bluetooth);
- if (err)
- return err;
- }
+ } else if (attr == &dev_attr_display.attr) {
+ supported = !acpi_check_handle(handle, METHOD_SWITCH_DISPLAY, NULL);
- if (!acpi_check_handle(asus->handle, METHOD_SWITCH_DISPLAY, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_display);
- if (err)
- return err;
- }
+ } else if (attr == &dev_attr_ledd.attr) {
+ supported = !acpi_check_handle(handle, METHOD_LEDD, NULL);
- if (!acpi_check_handle(asus->handle, METHOD_LEDD, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_ledd);
- if (err)
- return err;
- }
-
- if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
- !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_ls_switch);
- if (err)
- return err;
- err = device_create_file(&device->dev, &dev_attr_ls_level);
- if (err)
- return err;
- }
+ } else if (attr == &dev_attr_ls_switch.attr ||
+ attr == &dev_attr_ls_level.attr) {
+ supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) &&
+ !acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL);
- if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
- !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
- !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_gps);
- if (err)
- return err;
+ } else if (attr == &dev_attr_gps.attr) {
+ supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) &&
+ !acpi_check_handle(handle, METHOD_GPS_OFF, NULL) &&
+ !acpi_check_handle(handle, METHOD_GPS_STATUS, NULL);
+ } else {
+ supported = true;
}
- return err;
+ return supported ? attr->mode : 0;
}
+
+static const struct attribute_group asus_attr_group = {
+ .is_visible = asus_sysfs_is_visible,
+ .attrs = asus_attributes,
+};
+
static int asus_platform_init(struct asus_laptop *asus)
{
- int err;
+ int result;
asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1);
if (!asus->platform_device)
return -ENOMEM;
platform_set_drvdata(asus->platform_device, asus);
- err = platform_device_add(asus->platform_device);
- if (err)
+ result = platform_device_add(asus->platform_device);
+ if (result)
goto fail_platform_device;
- err = asus_sysfs_init(asus);
- if (err)
+ result = sysfs_create_group(&asus->platform_device->dev.kobj,
+ &asus_attr_group);
+ if (result)
goto fail_sysfs;
+
return 0;
fail_sysfs:
- asus_sysfs_exit(asus);
platform_device_del(asus->platform_device);
fail_platform_device:
platform_device_put(asus->platform_device);
- return err;
+ return result;
}
static void asus_platform_exit(struct asus_laptop *asus)
{
- asus_sysfs_exit(asus);
+ sysfs_remove_group(&asus->platform_device->dev.kobj, &asus_attr_group);
platform_device_unregister(asus->platform_device);
}
@@ -1428,8 +1417,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
return AE_OK;
}
-static bool asus_device_present;
-
static int __devinit asus_acpi_init(struct asus_laptop *asus)
{
int result = 0;
@@ -1474,6 +1461,8 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
return result;
}
+static bool asus_device_present;
+
static int __devinit asus_acpi_add(struct acpi_device *device)
{
struct asus_laptop *asus;
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 4413975912e0..cf8a89a0d8f5 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -25,6 +25,8 @@
#include <linux/mm.h>
#include <linux/i8042.h>
#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include "../../firmware/dcdbas.h"
#define BRIGHTNESS_TOKEN 0x7d
@@ -325,6 +327,75 @@ static const struct rfkill_ops dell_rfkill_ops = {
.query = dell_rfkill_query,
};
+static struct dentry *dell_laptop_dir;
+
+static int dell_debugfs_show(struct seq_file *s, void *data)
+{
+ int status;
+
+ get_buffer();
+ dell_send_request(buffer, 17, 11);
+ status = buffer->output[1];
+ release_buffer();
+
+ seq_printf(s, "status:\t0x%X\n", status);
+ seq_printf(s, "Bit 0 : Hardware switch supported: %lu\n",
+ status & BIT(0));
+ seq_printf(s, "Bit 1 : Wifi locator supported: %lu\n",
+ (status & BIT(1)) >> 1);
+ seq_printf(s, "Bit 2 : Wifi is supported: %lu\n",
+ (status & BIT(2)) >> 2);
+ seq_printf(s, "Bit 3 : Bluetooth is supported: %lu\n",
+ (status & BIT(3)) >> 3);
+ seq_printf(s, "Bit 4 : WWAN is supported: %lu\n",
+ (status & BIT(4)) >> 4);
+ seq_printf(s, "Bit 5 : Wireless keyboard supported: %lu\n",
+ (status & BIT(5)) >> 5);
+ seq_printf(s, "Bit 8 : Wifi is installed: %lu\n",
+ (status & BIT(8)) >> 8);
+ seq_printf(s, "Bit 9 : Bluetooth is installed: %lu\n",
+ (status & BIT(9)) >> 9);
+ seq_printf(s, "Bit 10: WWAN is installed: %lu\n",
+ (status & BIT(10)) >> 10);
+ seq_printf(s, "Bit 16: Hardware switch is on: %lu\n",
+ (status & BIT(16)) >> 16);
+ seq_printf(s, "Bit 17: Wifi is blocked: %lu\n",
+ (status & BIT(17)) >> 17);
+ seq_printf(s, "Bit 18: Bluetooth is blocked: %lu\n",
+ (status & BIT(18)) >> 18);
+ seq_printf(s, "Bit 19: WWAN is blocked: %lu\n",
+ (status & BIT(19)) >> 19);
+
+ seq_printf(s, "\nhwswitch_state:\t0x%X\n", hwswitch_state);
+ seq_printf(s, "Bit 0 : Wifi controlled by switch: %lu\n",
+ hwswitch_state & BIT(0));
+ seq_printf(s, "Bit 1 : Bluetooth controlled by switch: %lu\n",
+ (hwswitch_state & BIT(1)) >> 1);
+ seq_printf(s, "Bit 2 : WWAN controlled by switch: %lu\n",
+ (hwswitch_state & BIT(2)) >> 2);
+ seq_printf(s, "Bit 7 : Wireless switch config locked: %lu\n",
+ (hwswitch_state & BIT(7)) >> 7);
+ seq_printf(s, "Bit 8 : Wifi locator enabled: %lu\n",
+ (hwswitch_state & BIT(8)) >> 8);
+ seq_printf(s, "Bit 15: Wifi locator setting locked: %lu\n",
+ (hwswitch_state & BIT(15)) >> 15);
+
+ return 0;
+}
+
+static int dell_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dell_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations dell_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = dell_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static void dell_update_rfkill(struct work_struct *ignored)
{
if (wifi_rfkill)
@@ -556,6 +627,11 @@ static int __init dell_init(void)
goto fail_filter;
}
+ dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
+ if (dell_laptop_dir != NULL)
+ debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
+ &dell_debugfs_fops);
+
#ifdef CONFIG_ACPI
/* In the event of an ACPI backlight being available, don't
* register the platform controller.
@@ -615,6 +691,7 @@ fail_platform_driver:
static void __exit dell_exit(void)
{
+ debugfs_remove_recursive(dell_laptop_dir);
i8042_remove_filter(dell_laptop_i8042_filter);
cancel_delayed_work_sync(&dell_rfkill_work);
backlight_device_unregister(dell_backlight_device);
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 08fb70f6d9bf..77f1d55414c6 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <linux/string.h>
@@ -44,78 +45,70 @@ static int acpi_video;
MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
-struct key_entry {
- char type; /* See KE_* below */
- u16 code;
- u16 keycode;
-};
-
-enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
-
/*
* Certain keys are flagged as KE_IGNORE. All of these are either
* notifications (rather than requests for change) or are also sent
* via the keyboard controller so should not be sent again.
*/
-static struct key_entry dell_legacy_wmi_keymap[] = {
- {KE_KEY, 0xe045, KEY_PROG1},
- {KE_KEY, 0xe009, KEY_EJECTCD},
+static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
+ { KE_KEY, 0xe045, { KEY_PROG1 } },
+ { KE_KEY, 0xe009, { KEY_EJECTCD } },
/* These also contain the brightness level at offset 6 */
- {KE_KEY, 0xe006, KEY_BRIGHTNESSUP},
- {KE_KEY, 0xe005, KEY_BRIGHTNESSDOWN},
+ { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } },
/* Battery health status button */
- {KE_KEY, 0xe007, KEY_BATTERY},
+ { KE_KEY, 0xe007, { KEY_BATTERY } },
/* This is actually for all radios. Although physically a
* switch, the notification does not provide an indication of
* state and so it should be reported as a key */
- {KE_KEY, 0xe008, KEY_WLAN},
+ { KE_KEY, 0xe008, { KEY_WLAN } },
/* The next device is at offset 6, the active devices are at
offset 8 and the attached devices at offset 10 */
- {KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE},
+ { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } },
- {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
+ { KE_IGNORE, 0xe00c, { KEY_KBDILLUMTOGGLE } },
/* BIOS error detected */
- {KE_IGNORE, 0xe00d, KEY_RESERVED},
+ { KE_IGNORE, 0xe00d, { KEY_RESERVED } },
/* Wifi Catcher */
- {KE_KEY, 0xe011, KEY_PROG2},
+ { KE_KEY, 0xe011, {KEY_PROG2 } },
/* Ambient light sensor toggle */
- {KE_IGNORE, 0xe013, KEY_RESERVED},
-
- {KE_IGNORE, 0xe020, KEY_MUTE},
- {KE_IGNORE, 0xe02e, KEY_VOLUMEDOWN},
- {KE_IGNORE, 0xe030, KEY_VOLUMEUP},
- {KE_IGNORE, 0xe033, KEY_KBDILLUMUP},
- {KE_IGNORE, 0xe034, KEY_KBDILLUMDOWN},
- {KE_IGNORE, 0xe03a, KEY_CAPSLOCK},
- {KE_IGNORE, 0xe045, KEY_NUMLOCK},
- {KE_IGNORE, 0xe046, KEY_SCROLLLOCK},
- {KE_END, 0}
+ { KE_IGNORE, 0xe013, { KEY_RESERVED } },
+
+ { KE_IGNORE, 0xe020, { KEY_MUTE } },
+ { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },
+ { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } },
+ { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } },
+ { KE_IGNORE, 0xe034, { KEY_KBDILLUMDOWN } },
+ { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } },
+ { KE_IGNORE, 0xe045, { KEY_NUMLOCK } },
+ { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } },
+ { KE_END, 0 }
};
static bool dell_new_hk_type;
-struct dell_new_keymap_entry {
+struct dell_bios_keymap_entry {
u16 scancode;
u16 keycode;
};
-struct dell_hotkey_table {
+struct dell_bios_hotkey_table {
struct dmi_header header;
- struct dell_new_keymap_entry keymap[];
+ struct dell_bios_keymap_entry keymap[];
};
-static struct key_entry *dell_new_wmi_keymap;
+static const struct dell_bios_hotkey_table *dell_bios_hotkey_table;
-static u16 bios_to_linux_keycode[256] = {
+static const u16 bios_to_linux_keycode[256] __initconst = {
KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG,
KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -138,68 +131,11 @@ static u16 bios_to_linux_keycode[256] = {
KEY_PROG3
};
-
-static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap;
-
static struct input_dev *dell_wmi_input_dev;
-static struct key_entry *dell_wmi_get_entry_by_scancode(unsigned int code)
-{
- struct key_entry *key;
-
- for (key = dell_wmi_keymap; key->type != KE_END; key++)
- if (code == key->code)
- return key;
-
- return NULL;
-}
-
-static struct key_entry *dell_wmi_get_entry_by_keycode(unsigned int keycode)
-{
- struct key_entry *key;
-
- for (key = dell_wmi_keymap; key->type != KE_END; key++)
- if (key->type == KE_KEY && keycode == key->keycode)
- return key;
-
- return NULL;
-}
-
-static int dell_wmi_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct key_entry *key = dell_wmi_get_entry_by_scancode(scancode);
-
- if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int dell_wmi_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct key_entry *key;
- unsigned int old_keycode;
-
- key = dell_wmi_get_entry_by_scancode(scancode);
- if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!dell_wmi_get_entry_by_keycode(old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
- }
- return -EINVAL;
-}
-
static void dell_wmi_notify(u32 value, void *context)
{
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
- static struct key_entry *key;
union acpi_object *obj;
acpi_status status;
@@ -212,8 +148,10 @@ static void dell_wmi_notify(u32 value, void *context)
obj = (union acpi_object *)response.pointer;
if (obj && obj->type == ACPI_TYPE_BUFFER) {
+ const struct key_entry *key;
int reported_key;
u16 *buffer_entry = (u16 *)obj->buffer.pointer;
+
if (dell_new_hk_type && (buffer_entry[1] != 0x10)) {
printk(KERN_INFO "dell-wmi: Received unknown WMI event"
" (0x%x)\n", buffer_entry[1]);
@@ -226,8 +164,8 @@ static void dell_wmi_notify(u32 value, void *context)
else
reported_key = (int)buffer_entry[1] & 0xffff;
- key = dell_wmi_get_entry_by_scancode(reported_key);
-
+ key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
+ reported_key);
if (!key) {
printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
reported_key);
@@ -237,92 +175,98 @@ static void dell_wmi_notify(u32 value, void *context)
* come via ACPI */
;
} else {
- input_report_key(dell_wmi_input_dev, key->keycode, 1);
- input_sync(dell_wmi_input_dev);
- input_report_key(dell_wmi_input_dev, key->keycode, 0);
- input_sync(dell_wmi_input_dev);
+ sparse_keymap_report_entry(dell_wmi_input_dev, key,
+ 1, true);
}
}
kfree(obj);
}
-
-static void setup_new_hk_map(const struct dmi_header *dm)
+static const struct key_entry * __init dell_wmi_prepare_new_keymap(void)
{
-
+ int hotkey_num = (dell_bios_hotkey_table->header.length - 4) /
+ sizeof(struct dell_bios_keymap_entry);
+ struct key_entry *keymap;
int i;
- int hotkey_num = (dm->length-4)/sizeof(struct dell_new_keymap_entry);
- struct dell_hotkey_table *table =
- container_of(dm, struct dell_hotkey_table, header);
- dell_new_wmi_keymap = kzalloc((hotkey_num+1) *
- sizeof(struct key_entry), GFP_KERNEL);
+ keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL);
+ if (!keymap)
+ return NULL;
for (i = 0; i < hotkey_num; i++) {
- dell_new_wmi_keymap[i].type = KE_KEY;
- dell_new_wmi_keymap[i].code = table->keymap[i].scancode;
- dell_new_wmi_keymap[i].keycode =
- (table->keymap[i].keycode > 255) ? 0 :
- bios_to_linux_keycode[table->keymap[i].keycode];
+ const struct dell_bios_keymap_entry *bios_entry =
+ &dell_bios_hotkey_table->keymap[i];
+ keymap[i].type = KE_KEY;
+ keymap[i].code = bios_entry->scancode;
+ keymap[i].keycode = bios_entry->keycode < 256 ?
+ bios_to_linux_keycode[bios_entry->keycode] :
+ KEY_RESERVED;
}
- dell_new_wmi_keymap[i].type = KE_END;
- dell_new_wmi_keymap[i].code = 0;
- dell_new_wmi_keymap[i].keycode = 0;
-
- dell_wmi_keymap = dell_new_wmi_keymap;
+ keymap[hotkey_num].type = KE_END;
+ return keymap;
}
-
-static void find_hk_type(const struct dmi_header *dm, void *dummy)
-{
-
- if ((dm->type == 0xb2) && (dm->length > 6)) {
- dell_new_hk_type = true;
- setup_new_hk_map(dm);
- }
-
-}
-
-
static int __init dell_wmi_input_setup(void)
{
- struct key_entry *key;
int err;
dell_wmi_input_dev = input_allocate_device();
-
if (!dell_wmi_input_dev)
return -ENOMEM;
dell_wmi_input_dev->name = "Dell WMI hotkeys";
dell_wmi_input_dev->phys = "wmi/input0";
dell_wmi_input_dev->id.bustype = BUS_HOST;
- dell_wmi_input_dev->getkeycode = dell_wmi_getkeycode;
- dell_wmi_input_dev->setkeycode = dell_wmi_setkeycode;
-
- for (key = dell_wmi_keymap; key->type != KE_END; key++) {
- switch (key->type) {
- case KE_KEY:
- set_bit(EV_KEY, dell_wmi_input_dev->evbit);
- set_bit(key->keycode, dell_wmi_input_dev->keybit);
- break;
- case KE_SW:
- set_bit(EV_SW, dell_wmi_input_dev->evbit);
- set_bit(key->keycode, dell_wmi_input_dev->swbit);
- break;
+
+ if (dell_new_hk_type) {
+ const struct key_entry *keymap = dell_wmi_prepare_new_keymap();
+ if (!keymap) {
+ err = -ENOMEM;
+ goto err_free_dev;
}
- }
- err = input_register_device(dell_wmi_input_dev);
+ err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL);
- if (err) {
- input_free_device(dell_wmi_input_dev);
- return err;
+ /*
+ * Sparse keymap library makes a copy of keymap so we
+ * don't need the original one that was allocated.
+ */
+ kfree(keymap);
+ } else {
+ err = sparse_keymap_setup(dell_wmi_input_dev,
+ dell_wmi_legacy_keymap, NULL);
}
+ if (err)
+ goto err_free_dev;
+
+ err = input_register_device(dell_wmi_input_dev);
+ if (err)
+ goto err_free_keymap;
return 0;
+
+ err_free_keymap:
+ sparse_keymap_free(dell_wmi_input_dev);
+ err_free_dev:
+ input_free_device(dell_wmi_input_dev);
+ return err;
+}
+
+static void dell_wmi_input_destroy(void)
+{
+ sparse_keymap_free(dell_wmi_input_dev);
+ input_unregister_device(dell_wmi_input_dev);
+}
+
+static void __init find_hk_type(const struct dmi_header *dm, void *dummy)
+{
+ if (dm->type == 0xb2 && dm->length > 6) {
+ dell_new_hk_type = true;
+ dell_bios_hotkey_table =
+ container_of(dm, struct dell_bios_hotkey_table, header);
+ }
}
static int __init dell_wmi_init(void)
@@ -339,18 +283,13 @@ static int __init dell_wmi_init(void)
acpi_video = acpi_video_backlight_support();
err = dell_wmi_input_setup();
- if (err) {
- if (dell_new_hk_type)
- kfree(dell_wmi_keymap);
+ if (err)
return err;
- }
status = wmi_install_notify_handler(DELL_EVENT_GUID,
dell_wmi_notify, NULL);
if (ACPI_FAILURE(status)) {
- input_unregister_device(dell_wmi_input_dev);
- if (dell_new_hk_type)
- kfree(dell_wmi_keymap);
+ dell_wmi_input_destroy();
printk(KERN_ERR
"dell-wmi: Unable to register notify handler - %d\n",
status);
@@ -359,14 +298,11 @@ static int __init dell_wmi_init(void)
return 0;
}
+module_init(dell_wmi_init);
static void __exit dell_wmi_exit(void)
{
wmi_remove_notify_handler(DELL_EVENT_GUID);
- input_unregister_device(dell_wmi_input_dev);
- if (dell_new_hk_type)
- kfree(dell_wmi_keymap);
+ dell_wmi_input_destroy();
}
-
-module_init(dell_wmi_init);
module_exit(dell_wmi_exit);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 6b8e06206c46..b2edfdcdcb84 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -165,6 +165,7 @@ struct eeepc_laptop {
u16 event_count[128]; /* count for each event */
struct platform_device *platform_device;
+ struct acpi_device *device; /* the device we are in */
struct device *hwmon_device;
struct backlight_device *backlight_device;
@@ -1193,9 +1194,9 @@ static int eeepc_input_init(struct eeepc_laptop *eeepc)
eeepc->inputdev = input;
return 0;
- err_free_keymap:
+err_free_keymap:
sparse_keymap_free(input);
- err_free_dev:
+err_free_dev:
input_free_device(input);
return error;
}
@@ -1206,6 +1207,7 @@ static void eeepc_input_exit(struct eeepc_laptop *eeepc)
sparse_keymap_free(eeepc->inputdev);
input_unregister_device(eeepc->inputdev);
}
+ eeepc->inputdev = NULL;
}
/*
@@ -1326,16 +1328,15 @@ static void cmsg_quirks(struct eeepc_laptop *eeepc)
cmsg_quirk(eeepc, CM_ASL_TPD, "TPD");
}
-static int eeepc_acpi_init(struct eeepc_laptop *eeepc,
- struct acpi_device *device)
+static int __devinit eeepc_acpi_init(struct eeepc_laptop *eeepc)
{
unsigned int init_flags;
int result;
- result = acpi_bus_get_status(device);
+ result = acpi_bus_get_status(eeepc->device);
if (result)
return result;
- if (!device->status.present) {
+ if (!eeepc->device->status.present) {
pr_err("Hotkey device not present, aborting\n");
return -ENODEV;
}
@@ -1384,12 +1385,13 @@ static int __devinit eeepc_acpi_add(struct acpi_device *device)
strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);
strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
device->driver_data = eeepc;
+ eeepc->device = device;
eeepc->hotplug_disabled = hotplug_disabled;
eeepc_dmi_check(eeepc);
- result = eeepc_acpi_init(eeepc, device);
+ result = eeepc_acpi_init(eeepc);
if (result)
goto fail_platform;
eeepc_enable_camera(eeepc);
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 9dc50fbf3d0b..462ceab93f87 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -57,6 +57,7 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
#define EEEPC_WMI_METHODID_DEVS 0x53564544
#define EEEPC_WMI_METHODID_DSTS 0x53544344
+#define EEEPC_WMI_METHODID_CFVS 0x53564643
#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012
@@ -69,6 +70,11 @@ static const struct key_entry eeepc_wmi_keymap[] = {
{ KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } },
{ KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } },
{ KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */
+ { KE_KEY, 0xe1, { KEY_F14 } },
+ { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } },
+ { KE_KEY, 0xe0, { KEY_PROG1 } },
+ { KE_KEY, 0x5c, { KEY_F15 } },
{ KE_END, 0},
};
@@ -292,6 +298,49 @@ static void eeepc_wmi_notify(u32 value, void *context)
kfree(obj);
}
+static int store_cpufv(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ struct acpi_buffer input = { (acpi_size)sizeof(value), &value };
+ acpi_status status;
+
+ if (!count || sscanf(buf, "%i", &value) != 1)
+ return -EINVAL;
+ if (value < 0 || value > 2)
+ return -EINVAL;
+
+ status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
+ 1, EEEPC_WMI_METHODID_CFVS, &input, NULL);
+
+ if (ACPI_FAILURE(status))
+ return -EIO;
+ else
+ return count;
+}
+
+static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
+
+static void eeepc_wmi_sysfs_exit(struct platform_device *device)
+{
+ device_remove_file(&device->dev, &dev_attr_cpufv);
+}
+
+static int eeepc_wmi_sysfs_init(struct platform_device *device)
+{
+ int retval = -ENOMEM;
+
+ retval = device_create_file(&device->dev, &dev_attr_cpufv);
+ if (retval)
+ goto error_sysfs;
+
+ return 0;
+
+error_sysfs:
+ eeepc_wmi_sysfs_exit(platform_device);
+ return retval;
+}
+
static int __devinit eeepc_wmi_platform_probe(struct platform_device *device)
{
struct eeepc_wmi *eeepc;
@@ -387,8 +436,14 @@ static int __init eeepc_wmi_init(void)
goto del_dev;
}
+ err = eeepc_wmi_sysfs_init(platform_device);
+ if (err)
+ goto del_sysfs;
+
return 0;
+del_sysfs:
+ eeepc_wmi_sysfs_exit(platform_device);
del_dev:
platform_device_del(platform_device);
put_dev:
@@ -403,6 +458,7 @@ static void __exit eeepc_wmi_exit(void)
{
struct eeepc_wmi *eeepc;
+ eeepc_wmi_sysfs_exit(platform_device);
eeepc = platform_get_drvdata(platform_device);
platform_driver_unregister(&platform_driver);
platform_device_unregister(platform_device);
diff --git a/drivers/hwmon/hdaps.c b/drivers/platform/x86/hdaps.c
index bfd42f18924b..067bf36d32f3 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/platform/x86/hdaps.c
@@ -1,5 +1,5 @@
/*
- * drivers/hwmon/hdaps.c - driver for IBM's Hard Drive Active Protection System
+ * hdaps.c - driver for IBM's Hard Drive Active Protection System
*
* Copyright (C) 2005 Robert Love <rml@novell.com>
* Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index c1741142a4cb..1dac659b5e0c 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/rfkill.h>
@@ -88,24 +89,16 @@ struct bios_return {
u32 value;
};
-struct key_entry {
- char type; /* See KE_* below */
- u16 code;
- u16 keycode;
-};
-
-enum { KE_KEY, KE_END };
-
-static struct key_entry hp_wmi_keymap[] = {
- {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
- {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
- {KE_KEY, 0x20e6, KEY_PROG1},
- {KE_KEY, 0x20e8, KEY_MEDIA},
- {KE_KEY, 0x2142, KEY_MEDIA},
- {KE_KEY, 0x213b, KEY_INFO},
- {KE_KEY, 0x2169, KEY_DIRECTION},
- {KE_KEY, 0x231b, KEY_HELP},
- {KE_END, 0}
+static const struct key_entry hp_wmi_keymap[] = {
+ { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
+ { KE_KEY, 0x20e6, { KEY_PROG1 } },
+ { KE_KEY, 0x20e8, { KEY_MEDIA } },
+ { KE_KEY, 0x2142, { KEY_MEDIA } },
+ { KE_KEY, 0x213b, { KEY_INFO } },
+ { KE_KEY, 0x2169, { KEY_DIRECTION } },
+ { KE_KEY, 0x231b, { KEY_HELP } },
+ { KE_END, 0 }
};
static struct input_dev *hp_wmi_input_dev;
@@ -347,64 +340,9 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
-static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
-{
- struct key_entry *key;
-
- for (key = hp_wmi_keymap; key->type != KE_END; key++)
- if (code == key->code)
- return key;
-
- return NULL;
-}
-
-static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
-{
- struct key_entry *key;
-
- for (key = hp_wmi_keymap; key->type != KE_END; key++)
- if (key->type == KE_KEY && keycode == key->keycode)
- return key;
-
- return NULL;
-}
-
-static int hp_wmi_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
-
- if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int hp_wmi_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct key_entry *key;
- unsigned int old_keycode;
-
- key = hp_wmi_get_entry_by_scancode(scancode);
- if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!hp_wmi_get_entry_by_keycode(old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
- }
-
- return -EINVAL;
-}
-
static void hp_wmi_notify(u32 value, void *context)
{
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
- static struct key_entry *key;
union acpi_object *obj;
u32 event_id, event_data;
int key_code = 0, ret;
@@ -465,19 +403,9 @@ static void hp_wmi_notify(u32 value, void *context)
sizeof(key_code));
if (ret)
break;
- key = hp_wmi_get_entry_by_scancode(key_code);
- if (key) {
- switch (key->type) {
- case KE_KEY:
- input_report_key(hp_wmi_input_dev,
- key->keycode, 1);
- input_sync(hp_wmi_input_dev);
- input_report_key(hp_wmi_input_dev,
- key->keycode, 0);
- input_sync(hp_wmi_input_dev);
- break;
- }
- } else
+
+ if (!sparse_keymap_report_event(hp_wmi_input_dev,
+ key_code, 1, true))
printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
key_code);
break;
@@ -510,7 +438,7 @@ static void hp_wmi_notify(u32 value, void *context)
static int __init hp_wmi_input_setup(void)
{
- struct key_entry *key;
+ acpi_status status;
int err;
hp_wmi_input_dev = input_allocate_device();
@@ -520,21 +448,14 @@ static int __init hp_wmi_input_setup(void)
hp_wmi_input_dev->name = "HP WMI hotkeys";
hp_wmi_input_dev->phys = "wmi/input0";
hp_wmi_input_dev->id.bustype = BUS_HOST;
- hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
- hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
-
- for (key = hp_wmi_keymap; key->type != KE_END; key++) {
- switch (key->type) {
- case KE_KEY:
- set_bit(EV_KEY, hp_wmi_input_dev->evbit);
- set_bit(key->keycode, hp_wmi_input_dev->keybit);
- break;
- }
- }
- set_bit(EV_SW, hp_wmi_input_dev->evbit);
- set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
- set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+ __set_bit(EV_SW, hp_wmi_input_dev->evbit);
+ __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
+ __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+
+ err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
+ if (err)
+ goto err_free_dev;
/* Set initial hardware state */
input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
@@ -542,14 +463,32 @@ static int __init hp_wmi_input_setup(void)
hp_wmi_tablet_state());
input_sync(hp_wmi_input_dev);
- err = input_register_device(hp_wmi_input_dev);
-
- if (err) {
- input_free_device(hp_wmi_input_dev);
- return err;
+ status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ err = -EIO;
+ goto err_free_keymap;
}
+ err = input_register_device(hp_wmi_input_dev);
+ if (err)
+ goto err_uninstall_notifier;
+
return 0;
+
+ err_uninstall_notifier:
+ wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+ err_free_keymap:
+ sparse_keymap_free(hp_wmi_input_dev);
+ err_free_dev:
+ input_free_device(hp_wmi_input_dev);
+ return err;
+}
+
+static void hp_wmi_input_destroy(void)
+{
+ wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+ sparse_keymap_free(hp_wmi_input_dev);
+ input_unregister_device(hp_wmi_input_dev);
}
static void cleanup_sysfs(struct platform_device *device)
@@ -704,15 +643,9 @@ static int __init hp_wmi_init(void)
int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
if (event_capable) {
- err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
- hp_wmi_notify, NULL);
- if (ACPI_FAILURE(err))
- return -EINVAL;
err = hp_wmi_input_setup();
- if (err) {
- wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+ if (err)
return err;
- }
}
if (bios_capable) {
@@ -739,20 +672,17 @@ err_device_add:
err_device_alloc:
platform_driver_unregister(&hp_wmi_driver);
err_driver_reg:
- if (wmi_has_guid(HPWMI_EVENT_GUID)) {
- input_unregister_device(hp_wmi_input_dev);
- wmi_remove_notify_handler(HPWMI_EVENT_GUID);
- }
+ if (event_capable)
+ hp_wmi_input_destroy();
return err;
}
static void __exit hp_wmi_exit(void)
{
- if (wmi_has_guid(HPWMI_EVENT_GUID)) {
- wmi_remove_notify_handler(HPWMI_EVENT_GUID);
- input_unregister_device(hp_wmi_input_dev);
- }
+ if (wmi_has_guid(HPWMI_EVENT_GUID))
+ hp_wmi_input_destroy();
+
if (hp_wmi_platform_dev) {
platform_device_unregister(hp_wmi_platform_dev);
platform_driver_unregister(&hp_wmi_driver);
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
new file mode 100644
index 000000000000..3c2c6b91ecb3
--- /dev/null
+++ b/drivers/platform/x86/ibm_rtl.c
@@ -0,0 +1,341 @@
+/*
+ * IBM Real-Time Linux driver
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2010
+ *
+ * Author: Keith Mannthey <kmannth@us.ibm.com>
+ * Vernon Mauery <vernux@us.ibm.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/dmi.h>
+#include <linux/mutex.h>
+#include <asm/bios_ebda.h>
+
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Show debug output");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
+MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
+
+#define RTL_ADDR_TYPE_IO 1
+#define RTL_ADDR_TYPE_MMIO 2
+
+#define RTL_CMD_ENTER_PRTM 1
+#define RTL_CMD_EXIT_PRTM 2
+
+/* The RTL table as presented by the EBDA: */
+struct ibm_rtl_table {
+ char signature[5]; /* signature should be "_RTL_" */
+ u8 version;
+ u8 rt_status;
+ u8 command;
+ u8 command_status;
+ u8 cmd_address_type;
+ u8 cmd_granularity;
+ u8 cmd_offset;
+ u16 reserve1;
+ u32 cmd_port_address; /* platform dependent address */
+ u32 cmd_port_value; /* platform dependent value */
+} __attribute__((packed));
+
+/* to locate "_RTL_" signature do a masked 5-byte integer compare */
+#define RTL_SIGNATURE 0x0000005f4c54525fULL
+#define RTL_MASK 0x000000ffffffffffULL
+
+#define RTL_DEBUG(A, ...) do { \
+ if (debug) \
+ pr_info("ibm-rtl: " A, ##__VA_ARGS__ ); \
+} while (0)
+
+static DEFINE_MUTEX(rtl_lock);
+static struct ibm_rtl_table __iomem *rtl_table;
+static void __iomem *ebda_map;
+static void __iomem *rtl_cmd_addr;
+static u8 rtl_cmd_type;
+static u8 rtl_cmd_width;
+
+static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
+{
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ return ioremap(addr, len);
+ return ioport_map(addr, len);
+}
+
+static void rtl_port_unmap(void __iomem *addr)
+{
+ if (addr && rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iounmap(addr);
+ else
+ ioport_unmap(addr);
+}
+
+static int ibm_rtl_write(u8 value)
+{
+ int ret = 0, count = 0;
+ static u32 cmd_port_val;
+
+ RTL_DEBUG("%s(%d)\n", __FUNCTION__, value);
+
+ value = value == 1 ? RTL_CMD_ENTER_PRTM : RTL_CMD_EXIT_PRTM;
+
+ mutex_lock(&rtl_lock);
+
+ if (ioread8(&rtl_table->rt_status) != value) {
+ iowrite8(value, &rtl_table->command);
+
+ switch (rtl_cmd_width) {
+ case 8:
+ cmd_port_val = ioread8(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite8((u8)cmd_port_val, rtl_cmd_addr);
+ break;
+ case 16:
+ cmd_port_val = ioread16(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite16((u16)cmd_port_val, rtl_cmd_addr);
+ break;
+ case 32:
+ cmd_port_val = ioread32(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite32(cmd_port_val, rtl_cmd_addr);
+ break;
+ }
+
+ while (ioread8(&rtl_table->command)) {
+ msleep(10);
+ if (count++ > 500) {
+ pr_err("ibm-rtl: Hardware not responding to "
+ "mode switch request\n");
+ ret = -EIO;
+ break;
+ }
+
+ }
+
+ if (ioread8(&rtl_table->command_status)) {
+ RTL_DEBUG("command_status reports failed command\n");
+ ret = -EIO;
+ }
+ }
+
+ mutex_unlock(&rtl_lock);
+ return ret;
+}
+
+static ssize_t rtl_show_version(struct sysdev_class * dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version));
+}
+
+static ssize_t rtl_show_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status));
+}
+
+static ssize_t rtl_set_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ ssize_t ret;
+
+ if (count < 1 || count > 2)
+ return -EINVAL;
+
+ switch (buf[0]) {
+ case '0':
+ ret = ibm_rtl_write(0);
+ break;
+ case '1':
+ ret = ibm_rtl_write(1);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (ret >= 0)
+ ret = count;
+
+ return ret;
+}
+
+static struct sysdev_class class_rtl = {
+ .name = "ibm_rtl",
+};
+
+static SYSDEV_CLASS_ATTR(version, S_IRUGO, rtl_show_version, NULL);
+static SYSDEV_CLASS_ATTR(state, 0600, rtl_show_state, rtl_set_state);
+
+static struct sysdev_class_attribute *rtl_attributes[] = {
+ &attr_version,
+ &attr_state,
+ NULL
+};
+
+
+static int rtl_setup_sysfs(void) {
+ int ret, i;
+ ret = sysdev_class_register(&class_rtl);
+
+ if (!ret) {
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_create_file(&class_rtl, rtl_attributes[i]);
+ }
+ return ret;
+}
+
+static void rtl_teardown_sysfs(void) {
+ int i;
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_remove_file(&class_rtl, rtl_attributes[i]);
+ sysdev_class_unregister(&class_rtl);
+}
+
+static int dmi_check_cb(const struct dmi_system_id *id)
+{
+ RTL_DEBUG("found IBM server '%s'\n", id->ident);
+ return 0;
+}
+
+#define ibm_dmi_entry(NAME, TYPE) \
+{ \
+ .ident = NAME, \
+ .matches = { \
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \
+ }, \
+ .callback = dmi_check_cb \
+}
+
+static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
+ ibm_dmi_entry("BladeCenter LS21", "7971"),
+ ibm_dmi_entry("BladeCenter LS22", "7901"),
+ ibm_dmi_entry("BladeCenter HS21 XM", "7995"),
+ ibm_dmi_entry("BladeCenter HS22", "7870"),
+ ibm_dmi_entry("BladeCenter HS22V", "7871"),
+ ibm_dmi_entry("System x3550 M2", "7946"),
+ ibm_dmi_entry("System x3650 M2", "7947"),
+ ibm_dmi_entry("System x3550 M3", "7944"),
+ ibm_dmi_entry("System x3650 M3", "7945"),
+ { }
+};
+
+static int __init ibm_rtl_init(void) {
+ unsigned long ebda_addr, ebda_size;
+ unsigned int ebda_kb;
+ int ret = -ENODEV, i;
+
+ if (force)
+ pr_warning("ibm-rtl: module loaded by force\n");
+ /* first ensure that we are running on IBM HW */
+ else if (!dmi_check_system(ibm_rtl_dmi_table))
+ return -ENODEV;
+
+ /* Get the address for the Extended BIOS Data Area */
+ ebda_addr = get_bios_ebda();
+ if (!ebda_addr) {
+ RTL_DEBUG("no BIOS EBDA found\n");
+ return -ENODEV;
+ }
+
+ ebda_map = ioremap(ebda_addr, 4);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* First word in the EDBA is the Size in KB */
+ ebda_kb = ioread16(ebda_map);
+ RTL_DEBUG("EBDA is %d kB\n", ebda_kb);
+
+ if (ebda_kb == 0)
+ goto out;
+
+ iounmap(ebda_map);
+ ebda_size = ebda_kb*1024;
+
+ /* Remap the whole table */
+ ebda_map = ioremap(ebda_addr, ebda_size);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* search for the _RTL_ signature at the start of the table */
+ for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
+ struct ibm_rtl_table __iomem * tmp;
+ tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
+ if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) {
+ phys_addr_t addr;
+ unsigned int plen;
+ RTL_DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
+ rtl_table = tmp;
+ /* The address, value, width and offset are platform
+ * dependent and found in the ibm_rtl_table */
+ rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
+ rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
+ RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
+ rtl_cmd_width, rtl_cmd_type);
+ addr = ioread32(&rtl_table->cmd_port_address);
+ RTL_DEBUG("addr = %#llx\n", addr);
+ plen = rtl_cmd_width/sizeof(char);
+ rtl_cmd_addr = rtl_port_map(addr, plen);
+ RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
+ if (!rtl_cmd_addr) {
+ ret = -ENOMEM;
+ break;
+ }
+ ret = rtl_setup_sysfs();
+ break;
+ }
+ }
+
+out:
+ if (ret) {
+ iounmap(ebda_map);
+ rtl_port_unmap(rtl_cmd_addr);
+ }
+
+ return ret;
+}
+
+static void __exit ibm_rtl_exit(void)
+{
+ if (rtl_table) {
+ RTL_DEBUG("cleaning up");
+ /* do not leave the machine in SMI-free mode */
+ ibm_rtl_write(0);
+ /* unmap, unlink and remove all traces */
+ rtl_teardown_sysfs();
+ iounmap(ebda_map);
+ rtl_port_unmap(rtl_cmd_addr);
+ }
+}
+
+module_init(ibm_rtl_init);
+module_exit(ibm_rtl_exit);
diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad-laptop.c
index 798496353e8c..5ff12205aa6b 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -35,112 +35,162 @@
#define IDEAPAD_DEV_KILLSW 4
struct ideapad_private {
+ acpi_handle handle;
struct rfkill *rfk[5];
-};
+} *ideapad_priv;
static struct {
char *name;
+ int cfgbit;
+ int opcode;
int type;
} ideapad_rfk_data[] = {
- /* camera has no rfkill */
- { "ideapad_wlan", RFKILL_TYPE_WLAN },
- { "ideapad_bluetooth", RFKILL_TYPE_BLUETOOTH },
- { "ideapad_3g", RFKILL_TYPE_WWAN },
- { "ideapad_killsw", RFKILL_TYPE_WLAN }
+ { "ideapad_camera", 19, 0x1E, NUM_RFKILL_TYPES },
+ { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN },
+ { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH },
+ { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN },
+ { "ideapad_killsw", 0, 0, RFKILL_TYPE_WLAN }
};
-static int ideapad_dev_exists(int device)
-{
- acpi_status status;
- union acpi_object in_param;
- struct acpi_object_list input = { 1, &in_param };
- struct acpi_buffer output;
- union acpi_object out_obj;
+static bool no_bt_rfkill;
+module_param(no_bt_rfkill, bool, 0444);
+MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
+/*
+ * ACPI Helpers
+ */
+#define IDEAPAD_EC_TIMEOUT (100) /* in ms */
- in_param.type = ACPI_TYPE_INTEGER;
- in_param.integer.value = device + 1;
+static int read_method_int(acpi_handle handle, const char *method, int *val)
+{
+ acpi_status status;
+ unsigned long long result;
- status = acpi_evaluate_object(NULL, "\\_SB_.DECN", &input, &output);
+ status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.DECN method failed %d. Is this an IdeaPAD?\n", status);
- return -ENODEV;
- }
- if (out_obj.type != ACPI_TYPE_INTEGER) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.DECN method returned unexpected type\n");
- return -ENODEV;
+ *val = -1;
+ return -1;
+ } else {
+ *val = result;
+ return 0;
}
- return out_obj.integer.value;
}
-static int ideapad_dev_get_state(int device)
+static int method_vpcr(acpi_handle handle, int cmd, int *ret)
{
acpi_status status;
- union acpi_object in_param;
- struct acpi_object_list input = { 1, &in_param };
- struct acpi_buffer output;
- union acpi_object out_obj;
+ unsigned long long result;
+ struct acpi_object_list params;
+ union acpi_object in_obj;
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = cmd;
- in_param.type = ACPI_TYPE_INTEGER;
- in_param.integer.value = device + 1;
+ status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
- status = acpi_evaluate_object(NULL, "\\_SB_.GECN", &input, &output);
if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.GECN method failed %d\n", status);
- return -ENODEV;
- }
- if (out_obj.type != ACPI_TYPE_INTEGER) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.GECN method returned unexpected type\n");
- return -ENODEV;
+ *ret = -1;
+ return -1;
+ } else {
+ *ret = result;
+ return 0;
}
- return out_obj.integer.value;
}
-static int ideapad_dev_set_state(int device, int state)
+static int method_vpcw(acpi_handle handle, int cmd, int data)
{
+ struct acpi_object_list params;
+ union acpi_object in_obj[2];
acpi_status status;
- union acpi_object in_params[2];
- struct acpi_object_list input = { 2, in_params };
- in_params[0].type = ACPI_TYPE_INTEGER;
- in_params[0].integer.value = device + 1;
- in_params[1].type = ACPI_TYPE_INTEGER;
- in_params[1].integer.value = state;
+ params.count = 2;
+ params.pointer = in_obj;
+ in_obj[0].type = ACPI_TYPE_INTEGER;
+ in_obj[0].integer.value = cmd;
+ in_obj[1].type = ACPI_TYPE_INTEGER;
+ in_obj[1].integer.value = data;
- status = acpi_evaluate_object(NULL, "\\_SB_.SECN", &input, NULL);
- if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.SECN method failed %d\n", status);
- return -ENODEV;
- }
+ status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
+ if (status != AE_OK)
+ return -1;
return 0;
}
+
+static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
+{
+ int val;
+ unsigned long int end_jiffies;
+
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
+ time_before(jiffies, end_jiffies);) {
+ schedule();
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0) {
+ if (method_vpcr(handle, 0, &val))
+ return -1;
+ *data = val;
+ return 0;
+ }
+ }
+ pr_err("timeout in read_ec_cmd\n");
+ return -1;
+}
+
+static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
+{
+ int val;
+ unsigned long int end_jiffies;
+
+ if (method_vpcw(handle, 0, data))
+ return -1;
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
+ time_before(jiffies, end_jiffies);) {
+ schedule();
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0)
+ return 0;
+ }
+ pr_err("timeout in write_ec_cmd\n");
+ return -1;
+}
+/* the above is ACPI helpers */
+
static ssize_t show_ideapad_cam(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int state = ideapad_dev_get_state(IDEAPAD_DEV_CAMERA);
- if (state < 0)
- return state;
+ struct ideapad_private *priv = dev_get_drvdata(dev);
+ acpi_handle handle = priv->handle;
+ unsigned long result;
- return sprintf(buf, "%d\n", state);
+ if (read_ec_data(handle, 0x1D, &result))
+ return sprintf(buf, "-1\n");
+ return sprintf(buf, "%lu\n", result);
}
static ssize_t store_ideapad_cam(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct ideapad_private *priv = dev_get_drvdata(dev);
+ acpi_handle handle = priv->handle;
int ret, state;
if (!count)
return 0;
if (sscanf(buf, "%i", &state) != 1)
return -EINVAL;
- ret = ideapad_dev_set_state(IDEAPAD_DEV_CAMERA, !!state);
+ ret = write_ec_cmd(handle, 0x1E, state);
if (ret < 0)
return ret;
return count;
@@ -154,7 +204,10 @@ static int ideapad_rfk_set(void *data, bool blocked)
if (device == IDEAPAD_DEV_KILLSW)
return -EINVAL;
- return ideapad_dev_set_state(device, !blocked);
+
+ return write_ec_cmd(ideapad_priv->handle,
+ ideapad_rfk_data[device].opcode,
+ !blocked);
}
static struct rfkill_ops ideapad_rfk_ops = {
@@ -164,32 +217,47 @@ static struct rfkill_ops ideapad_rfk_ops = {
static void ideapad_sync_rfk_state(struct acpi_device *adevice)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
- int hw_blocked = !ideapad_dev_get_state(IDEAPAD_DEV_KILLSW);
+ acpi_handle handle = priv->handle;
+ unsigned long hw_blocked;
int i;
- rfkill_set_hw_state(priv->rfk[IDEAPAD_DEV_KILLSW], hw_blocked);
- for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++)
- if (priv->rfk[i])
- rfkill_set_hw_state(priv->rfk[i], hw_blocked);
- if (hw_blocked)
+ if (read_ec_data(handle, 0x23, &hw_blocked))
return;
+ hw_blocked = !hw_blocked;
- for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++)
+ for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
if (priv->rfk[i])
- rfkill_set_sw_state(priv->rfk[i], !ideapad_dev_get_state(i));
+ rfkill_set_hw_state(priv->rfk[i], hw_blocked);
}
static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
int ret;
+ unsigned long sw_blocked;
+
+ if (no_bt_rfkill &&
+ (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) {
+ /* Force to enable bluetooth when no_bt_rfkill=1 */
+ write_ec_cmd(ideapad_priv->handle,
+ ideapad_rfk_data[dev].opcode, 1);
+ return 0;
+ }
- priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev-1].name, &adevice->dev,
- ideapad_rfk_data[dev-1].type, &ideapad_rfk_ops,
+ priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name, &adevice->dev,
+ ideapad_rfk_data[dev].type, &ideapad_rfk_ops,
(void *)(long)dev);
if (!priv->rfk[dev])
return -ENOMEM;
+ if (read_ec_data(ideapad_priv->handle, ideapad_rfk_data[dev].opcode-1,
+ &sw_blocked)) {
+ rfkill_init_sw_state(priv->rfk[dev], 0);
+ } else {
+ sw_blocked = !sw_blocked;
+ rfkill_init_sw_state(priv->rfk[dev], sw_blocked);
+ }
+
ret = rfkill_register(priv->rfk[dev]);
if (ret) {
rfkill_destroy(priv->rfk[dev]);
@@ -217,14 +285,18 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
static int ideapad_acpi_add(struct acpi_device *adevice)
{
- int i;
+ int i, cfg;
int devs_present[5];
struct ideapad_private *priv;
+ if (read_method_int(adevice->handle, "_CFG", &cfg))
+ return -ENODEV;
+
for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) {
- devs_present[i] = ideapad_dev_exists(i);
- if (devs_present[i] < 0)
- return devs_present[i];
+ if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
+ devs_present[i] = 1;
+ else
+ devs_present[i] = 0;
}
/* The hardware switch is always present */
@@ -242,7 +314,9 @@ static int ideapad_acpi_add(struct acpi_device *adevice)
}
}
+ priv->handle = adevice->handle;
dev_set_drvdata(&adevice->dev, priv);
+ ideapad_priv = priv;
for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) {
if (!devs_present[i])
continue;
@@ -270,7 +344,21 @@ static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
{
- ideapad_sync_rfk_state(adevice);
+ acpi_handle handle = adevice->handle;
+ unsigned long vpc1, vpc2, vpc_bit;
+
+ if (read_ec_data(handle, 0x10, &vpc1))
+ return;
+ if (read_ec_data(handle, 0x1A, &vpc2))
+ return;
+
+ vpc1 = (vpc2 << 8) | vpc1;
+ for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
+ if (test_bit(vpc_bit, &vpc1)) {
+ if (vpc_bit == 9)
+ ideapad_sync_rfk_state(adevice);
+ }
+ }
}
static struct acpi_driver ideapad_acpi_driver = {
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
index 5cdcff653918..f540ff96c53f 100644
--- a/drivers/platform/x86/intel_pmic_gpio.c
+++ b/drivers/platform/x86/intel_pmic_gpio.c
@@ -142,16 +142,16 @@ static int pmic_gpio_direction_output(struct gpio_chip *chip,
if (offset < 8)/* it is GPIO */
rc = intel_scu_ipc_update_register(GPIO0 + offset,
- GPIO_DRV | GPIO_DOU | GPIO_DIR,
- GPIO_DRV | (value ? GPIO_DOU : 0));
+ GPIO_DRV | (value ? GPIO_DOU : 0),
+ GPIO_DRV | GPIO_DOU | GPIO_DIR);
else if (offset < 16)/* it is GPOSW */
rc = intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
- GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV,
- GPOSW_DRV | (value ? GPOSW_DOU : 0));
+ GPOSW_DRV | (value ? GPOSW_DOU : 0),
+ GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV);
else if (offset > 15 && offset < 24)/* it is GPO */
rc = intel_scu_ipc_update_register(GPO,
- 1 << (offset - 16),
- value ? 1 << (offset - 16) : 0);
+ value ? 1 << (offset - 16) : 0,
+ 1 << (offset - 16));
else {
printk(KERN_ERR
"%s: invalid PMIC GPIO pin %d!\n", __func__, offset);
@@ -179,16 +179,16 @@ static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
if (offset < 8)/* it is GPIO */
intel_scu_ipc_update_register(GPIO0 + offset,
- GPIO_DRV | GPIO_DOU,
- GPIO_DRV | (value ? GPIO_DOU : 0));
+ GPIO_DRV | (value ? GPIO_DOU : 0),
+ GPIO_DRV | GPIO_DOU);
else if (offset < 16)/* it is GPOSW */
intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
- GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV,
- GPOSW_DRV | (value ? GPOSW_DOU : 0));
+ GPOSW_DRV | (value ? GPOSW_DOU : 0),
+ GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV);
else if (offset > 15 && offset < 24) /* it is GPO */
intel_scu_ipc_update_register(GPO,
- 1 << (offset - 16),
- value ? 1 << (offset - 16) : 0);
+ value ? 1 << (offset - 16) : 0,
+ 1 << (offset - 16));
}
static int pmic_irq_type(unsigned irq, unsigned type)
@@ -197,7 +197,7 @@ static int pmic_irq_type(unsigned irq, unsigned type)
u32 gpio = irq - pg->irq_base;
unsigned long flags;
- if (gpio > pg->chip.ngpio)
+ if (gpio >= pg->chip.ngpio)
return -EINVAL;
spin_lock_irqsave(&pg->irqtypes.lock, flags);
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 6abe18e638e9..41a9e34899ac 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -23,6 +23,7 @@
#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/sfi.h>
#include <asm/mrst.h>
#include <asm/intel_scu_ipc.h>
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index ec01c3d8fc5a..cc1e0ba104d7 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -128,6 +128,7 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#ifndef ACPI_HOTKEY_COMPONENT
@@ -200,30 +201,29 @@ static struct acpi_driver acpi_pcc_driver = {
},
};
-#define KEYMAP_SIZE 11
-static const unsigned int initial_keymap[KEYMAP_SIZE] = {
- /* 0 */ KEY_RESERVED,
- /* 1 */ KEY_BRIGHTNESSDOWN,
- /* 2 */ KEY_BRIGHTNESSUP,
- /* 3 */ KEY_DISPLAYTOGGLE,
- /* 4 */ KEY_MUTE,
- /* 5 */ KEY_VOLUMEDOWN,
- /* 6 */ KEY_VOLUMEUP,
- /* 7 */ KEY_SLEEP,
- /* 8 */ KEY_PROG1, /* Change CPU boost */
- /* 9 */ KEY_BATTERY,
- /* 10 */ KEY_SUSPEND,
+static const struct key_entry panasonic_keymap[] = {
+ { KE_KEY, 0, { KEY_RESERVED } },
+ { KE_KEY, 1, { KEY_BRIGHTNESSDOWN } },
+ { KE_KEY, 2, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 3, { KEY_DISPLAYTOGGLE } },
+ { KE_KEY, 4, { KEY_MUTE } },
+ { KE_KEY, 5, { KEY_VOLUMEDOWN } },
+ { KE_KEY, 6, { KEY_VOLUMEUP } },
+ { KE_KEY, 7, { KEY_SLEEP } },
+ { KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */
+ { KE_KEY, 9, { KEY_BATTERY } },
+ { KE_KEY, 10, { KEY_SUSPEND } },
+ { KE_END, 0 }
};
struct pcc_acpi {
acpi_handle handle;
unsigned long num_sifr;
int sticky_mode;
- u32 *sinf;
+ u32 *sinf;
struct acpi_device *device;
struct input_dev *input_dev;
struct backlight_device *backlight;
- unsigned int keymap[KEYMAP_SIZE];
};
struct pcc_keyinput {
@@ -267,7 +267,7 @@ static inline int acpi_pcc_get_sqty(struct acpi_device *device)
}
}
-static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
+static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc)
{
acpi_status status;
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -285,6 +285,7 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
hkey = buffer.pointer;
if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n"));
+ status = AE_ERROR;
goto end;
}
@@ -298,12 +299,12 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
for (i = 0; i < hkey->package.count; i++) {
union acpi_object *element = &(hkey->package.elements[i]);
if (likely(element->type == ACPI_TYPE_INTEGER)) {
- sinf[i] = element->integer.value;
+ pcc->sinf[i] = element->integer.value;
} else
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid HKEY.SINF data\n"));
}
- sinf[hkey->package.count] = -1;
+ pcc->sinf[hkey->package.count] = -1;
end:
kfree(buffer.pointer);
@@ -321,7 +322,7 @@ static int bl_get(struct backlight_device *bd)
{
struct pcc_acpi *pcc = bl_get_data(bd);
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return pcc->sinf[SINF_AC_CUR_BRIGHT];
@@ -333,7 +334,7 @@ static int bl_set_status(struct backlight_device *bd)
int bright = bd->props.brightness;
int rc;
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT])
@@ -367,7 +368,7 @@ static ssize_t show_numbatt(struct device *dev, struct device_attribute *attr,
struct acpi_device *acpi = to_acpi_device(dev);
struct pcc_acpi *pcc = acpi_driver_data(acpi);
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
@@ -379,7 +380,7 @@ static ssize_t show_lcdtype(struct device *dev, struct device_attribute *attr,
struct acpi_device *acpi = to_acpi_device(dev);
struct pcc_acpi *pcc = acpi_driver_data(acpi);
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
@@ -391,7 +392,7 @@ static ssize_t show_mute(struct device *dev, struct device_attribute *attr,
struct acpi_device *acpi = to_acpi_device(dev);
struct pcc_acpi *pcc = acpi_driver_data(acpi);
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_MUTE]);
@@ -403,7 +404,7 @@ static ssize_t show_sticky(struct device *dev, struct device_attribute *attr,
struct acpi_device *acpi = to_acpi_device(dev);
struct pcc_acpi *pcc = acpi_driver_data(acpi);
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_STICKY_KEY]);
@@ -446,56 +447,10 @@ static struct attribute_group pcc_attr_group = {
/* hotkey input device driver */
-static int pcc_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct pcc_acpi *pcc = input_get_drvdata(dev);
-
- if (scancode >= ARRAY_SIZE(pcc->keymap))
- return -EINVAL;
-
- *keycode = pcc->keymap[scancode];
-
- return 0;
-}
-
-static int keymap_get_by_keycode(struct pcc_acpi *pcc, unsigned int keycode)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) {
- if (pcc->keymap[i] == keycode)
- return i+1;
- }
-
- return 0;
-}
-
-static int pcc_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct pcc_acpi *pcc = input_get_drvdata(dev);
- int oldkeycode;
-
- if (scancode >= ARRAY_SIZE(pcc->keymap))
- return -EINVAL;
-
- oldkeycode = pcc->keymap[scancode];
- pcc->keymap[scancode] = keycode;
-
- set_bit(keycode, dev->keybit);
-
- if (!keymap_get_by_keycode(pcc, oldkeycode))
- clear_bit(oldkeycode, dev->keybit);
-
- return 0;
-}
-
static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
{
struct input_dev *hotk_input_dev = pcc->input_dev;
int rc;
- int key_code, hkey_num;
unsigned long long result;
rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
@@ -508,25 +463,10 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
- hkey_num = result & 0xf;
-
- if (hkey_num < 0 || hkey_num >= ARRAY_SIZE(pcc->keymap)) {
+ if (!sparse_keymap_report_event(hotk_input_dev,
+ result & 0xf, result & 0x80, false))
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "hotkey number out of range: %d\n",
- hkey_num));
- return;
- }
-
- key_code = pcc->keymap[hkey_num];
-
- if (key_code != KEY_RESERVED) {
- int pushed = (result & 0x80) ? TRUE : FALSE;
-
- input_report_key(hotk_input_dev, key_code, pushed);
- input_sync(hotk_input_dev);
- }
-
- return;
+ "Unknown hotkey event: %d\n", result));
}
static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
@@ -545,40 +485,55 @@ static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
static int acpi_pcc_init_input(struct pcc_acpi *pcc)
{
- int i, rc;
+ struct input_dev *input_dev;
+ int error;
- pcc->input_dev = input_allocate_device();
- if (!pcc->input_dev) {
+ input_dev = input_allocate_device();
+ if (!input_dev) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Couldn't allocate input device for hotkey"));
return -ENOMEM;
}
- pcc->input_dev->evbit[0] = BIT(EV_KEY);
-
- pcc->input_dev->name = ACPI_PCC_DRIVER_NAME;
- pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS;
- pcc->input_dev->id.bustype = BUS_HOST;
- pcc->input_dev->id.vendor = 0x0001;
- pcc->input_dev->id.product = 0x0001;
- pcc->input_dev->id.version = 0x0100;
- pcc->input_dev->getkeycode = pcc_getkeycode;
- pcc->input_dev->setkeycode = pcc_setkeycode;
+ input_dev->name = ACPI_PCC_DRIVER_NAME;
+ input_dev->phys = ACPI_PCC_INPUT_PHYS;
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
- /* load initial keymap */
- memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap));
+ error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL);
+ if (error) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to setup input device keymap\n"));
+ goto err_free_dev;
+ }
- for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++)
- __set_bit(pcc->keymap[i], pcc->input_dev->keybit);
- __clear_bit(KEY_RESERVED, pcc->input_dev->keybit);
+ error = input_register_device(input_dev);
+ if (error) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to register input device\n"));
+ goto err_free_keymap;
+ }
- input_set_drvdata(pcc->input_dev, pcc);
+ pcc->input_dev = input_dev;
+ return 0;
- rc = input_register_device(pcc->input_dev);
- if (rc < 0)
- input_free_device(pcc->input_dev);
+ err_free_keymap:
+ sparse_keymap_free(input_dev);
+ err_free_dev:
+ input_free_device(input_dev);
+ return error;
+}
- return rc;
+static void acpi_pcc_destroy_input(struct pcc_acpi *pcc)
+{
+ sparse_keymap_free(pcc->input_dev);
+ input_unregister_device(pcc->input_dev);
+ /*
+ * No need to input_free_device() since core input API refcounts
+ * and free()s the device.
+ */
}
/* kernel module interface */
@@ -636,12 +591,13 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error installing keyinput handler\n"));
- goto out_hotkey;
+ goto out_sinf;
}
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) {
+ if (!acpi_pcc_retrieve_biosdata(pcc)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Couldn't retrieve BIOS data\n"));
+ result = -EIO;
goto out_input;
}
/* initialize backlight */
@@ -651,7 +607,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
&pcc_backlight_ops, &props);
if (IS_ERR(pcc->backlight)) {
result = PTR_ERR(pcc->backlight);
- goto out_sinf;
+ goto out_input;
}
/* read the initial brightness setting from the hardware */
@@ -669,12 +625,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
out_backlight:
backlight_device_unregister(pcc->backlight);
+out_input:
+ acpi_pcc_destroy_input(pcc);
out_sinf:
kfree(pcc->sinf);
-out_input:
- input_unregister_device(pcc->input_dev);
- /* no need to input_free_device() since core input API refcount and
- * free()s the device */
out_hotkey:
kfree(pcc);
@@ -709,9 +663,7 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
backlight_device_unregister(pcc->backlight);
- input_unregister_device(pcc->input_dev);
- /* no need to input_free_device() since core input API refcount and
- * free()s the device */
+ acpi_pcc_destroy_input(pcc);
kfree(pcc->sinf);
kfree(pcc);
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index ff4b476f1950..1d07d6d09f27 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -19,6 +19,7 @@
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#define ACPI_TOPSTAR_CLASS "topstar"
@@ -26,52 +27,37 @@ struct topstar_hkey {
struct input_dev *inputdev;
};
-struct tps_key_entry {
- u8 code;
- u16 keycode;
-};
-
-static struct tps_key_entry topstar_keymap[] = {
- { 0x80, KEY_BRIGHTNESSUP },
- { 0x81, KEY_BRIGHTNESSDOWN },
- { 0x83, KEY_VOLUMEUP },
- { 0x84, KEY_VOLUMEDOWN },
- { 0x85, KEY_MUTE },
- { 0x86, KEY_SWITCHVIDEOMODE },
- { 0x87, KEY_F13 }, /* touchpad enable/disable key */
- { 0x88, KEY_WLAN },
- { 0x8a, KEY_WWW },
- { 0x8b, KEY_MAIL },
- { 0x8c, KEY_MEDIA },
- { 0x96, KEY_F14 }, /* G key? */
- { }
-};
-
-static struct tps_key_entry *tps_get_key_by_scancode(unsigned int code)
-{
- struct tps_key_entry *key;
-
- for (key = topstar_keymap; key->code; key++)
- if (code == key->code)
- return key;
+static const struct key_entry topstar_keymap[] = {
+ { KE_KEY, 0x80, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 0x81, { KEY_BRIGHTNESSDOWN } },
+ { KE_KEY, 0x83, { KEY_VOLUMEUP } },
+ { KE_KEY, 0x84, { KEY_VOLUMEDOWN } },
+ { KE_KEY, 0x85, { KEY_MUTE } },
+ { KE_KEY, 0x86, { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, 0x87, { KEY_F13 } }, /* touchpad enable/disable key */
+ { KE_KEY, 0x88, { KEY_WLAN } },
+ { KE_KEY, 0x8a, { KEY_WWW } },
+ { KE_KEY, 0x8b, { KEY_MAIL } },
+ { KE_KEY, 0x8c, { KEY_MEDIA } },
- return NULL;
-}
-
-static struct tps_key_entry *tps_get_key_by_keycode(unsigned int code)
-{
- struct tps_key_entry *key;
+ /* Known non hotkey events don't handled or that we don't care yet */
+ { KE_IGNORE, 0x8e, },
+ { KE_IGNORE, 0x8f, },
+ { KE_IGNORE, 0x90, },
- for (key = topstar_keymap; key->code; key++)
- if (code == key->keycode)
- return key;
+ /*
+ * 'G key' generate two event codes, convert to only
+ * one event/key code for now, consider replacing by
+ * a switch (3G switch - SW_3G?)
+ */
+ { KE_KEY, 0x96, { KEY_F14 } },
+ { KE_KEY, 0x97, { KEY_F14 } },
- return NULL;
-}
+ { KE_END, 0 }
+};
static void acpi_topstar_notify(struct acpi_device *device, u32 event)
{
- struct tps_key_entry *key;
static bool dup_evnt[2];
bool *dup;
struct topstar_hkey *hkey = acpi_driver_data(device);
@@ -86,27 +72,8 @@ static void acpi_topstar_notify(struct acpi_device *device, u32 event)
*dup = true;
}
- /*
- * 'G key' generate two event codes, convert to only
- * one event/key code for now (3G switch?)
- */
- if (event == 0x97)
- event = 0x96;
-
- key = tps_get_key_by_scancode(event);
- if (key) {
- input_report_key(hkey->inputdev, key->keycode, 1);
- input_sync(hkey->inputdev);
- input_report_key(hkey->inputdev, key->keycode, 0);
- input_sync(hkey->inputdev);
- return;
- }
-
- /* Known non hotkey events don't handled or that we don't care yet */
- if (event == 0x8e || event == 0x8f || event == 0x90)
- return;
-
- pr_info("unknown event = 0x%02x\n", event);
+ if (!sparse_keymap_report_event(hkey->inputdev, event, 1, true))
+ pr_info("unknown event = 0x%02x\n", event);
}
static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
@@ -127,62 +94,41 @@ static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
return 0;
}
-static int topstar_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct tps_key_entry *key = tps_get_key_by_scancode(scancode);
-
- if (!key)
- return -EINVAL;
-
- *keycode = key->keycode;
- return 0;
-}
-
-static int topstar_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct tps_key_entry *key;
- int old_keycode;
-
- key = tps_get_key_by_scancode(scancode);
-
- if (!key)
- return -EINVAL;
-
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!tps_get_key_by_keycode(old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
-}
-
static int acpi_topstar_init_hkey(struct topstar_hkey *hkey)
{
- struct tps_key_entry *key;
+ struct input_dev *input;
+ int error;
- hkey->inputdev = input_allocate_device();
- if (!hkey->inputdev) {
+ input = input_allocate_device();
+ if (!input) {
pr_err("Unable to allocate input device\n");
- return -ENODEV;
+ return -ENOMEM;
}
- hkey->inputdev->name = "Topstar Laptop extra buttons";
- hkey->inputdev->phys = "topstar/input0";
- hkey->inputdev->id.bustype = BUS_HOST;
- hkey->inputdev->getkeycode = topstar_getkeycode;
- hkey->inputdev->setkeycode = topstar_setkeycode;
- for (key = topstar_keymap; key->code; key++) {
- set_bit(EV_KEY, hkey->inputdev->evbit);
- set_bit(key->keycode, hkey->inputdev->keybit);
+
+ input->name = "Topstar Laptop extra buttons";
+ input->phys = "topstar/input0";
+ input->id.bustype = BUS_HOST;
+
+ error = sparse_keymap_setup(input, topstar_keymap, NULL);
+ if (error) {
+ pr_err("Unable to setup input device keymap\n");
+ goto err_free_dev;
}
- if (input_register_device(hkey->inputdev)) {
+
+ error = input_register_device(input);
+ if (error) {
pr_err("Unable to register input device\n");
- input_free_device(hkey->inputdev);
- return -ENODEV;
+ goto err_free_keymap;
}
+ hkey->inputdev = input;
return 0;
+
+ err_free_keymap:
+ sparse_keymap_free(input);
+ err_free_dev:
+ input_free_device(input);
+ return error;
}
static int acpi_topstar_add(struct acpi_device *device)
@@ -216,6 +162,7 @@ static int acpi_topstar_remove(struct acpi_device *device, int type)
acpi_topstar_fncx_switch(device, false);
+ sparse_keymap_free(tps_hkey->inputdev);
input_unregister_device(tps_hkey->inputdev);
kfree(tps_hkey);
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 7d67a45bb2b0..06f304f46e02 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -48,6 +48,7 @@
#include <linux/platform_device.h>
#include <linux/rfkill.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#include <linux/leds.h>
#include <linux/slab.h>
@@ -121,36 +122,28 @@ static const struct acpi_device_id toshiba_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
-struct key_entry {
- char type;
- u16 code;
- u16 keycode;
-};
-
-enum {KE_KEY, KE_END};
-
-static struct key_entry toshiba_acpi_keymap[] = {
- {KE_KEY, 0x101, KEY_MUTE},
- {KE_KEY, 0x102, KEY_ZOOMOUT},
- {KE_KEY, 0x103, KEY_ZOOMIN},
- {KE_KEY, 0x13b, KEY_COFFEE},
- {KE_KEY, 0x13c, KEY_BATTERY},
- {KE_KEY, 0x13d, KEY_SLEEP},
- {KE_KEY, 0x13e, KEY_SUSPEND},
- {KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
- {KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
- {KE_KEY, 0x141, KEY_BRIGHTNESSUP},
- {KE_KEY, 0x142, KEY_WLAN},
- {KE_KEY, 0x143, KEY_PROG1},
- {KE_KEY, 0xb05, KEY_PROG2},
- {KE_KEY, 0xb06, KEY_WWW},
- {KE_KEY, 0xb07, KEY_MAIL},
- {KE_KEY, 0xb30, KEY_STOP},
- {KE_KEY, 0xb31, KEY_PREVIOUSSONG},
- {KE_KEY, 0xb32, KEY_NEXTSONG},
- {KE_KEY, 0xb33, KEY_PLAYPAUSE},
- {KE_KEY, 0xb5a, KEY_MEDIA},
- {KE_END, 0, 0},
+static const struct key_entry toshiba_acpi_keymap[] __initconst = {
+ { KE_KEY, 0x101, { KEY_MUTE } },
+ { KE_KEY, 0x102, { KEY_ZOOMOUT } },
+ { KE_KEY, 0x103, { KEY_ZOOMIN } },
+ { KE_KEY, 0x13b, { KEY_COFFEE } },
+ { KE_KEY, 0x13c, { KEY_BATTERY } },
+ { KE_KEY, 0x13d, { KEY_SLEEP } },
+ { KE_KEY, 0x13e, { KEY_SUSPEND } },
+ { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
+ { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 0x142, { KEY_WLAN } },
+ { KE_KEY, 0x143, { KEY_PROG1 } },
+ { KE_KEY, 0xb05, { KEY_PROG2 } },
+ { KE_KEY, 0xb06, { KEY_WWW } },
+ { KE_KEY, 0xb07, { KEY_MAIL } },
+ { KE_KEY, 0xb30, { KEY_STOP } },
+ { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
+ { KE_KEY, 0xb32, { KEY_NEXTSONG } },
+ { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
+ { KE_KEY, 0xb5a, { KEY_MEDIA } },
+ { KE_END, 0 },
};
/* utility
@@ -852,64 +845,9 @@ static struct backlight_ops toshiba_backlight_data = {
.update_status = set_lcd_status,
};
-static struct key_entry *toshiba_acpi_get_entry_by_scancode(unsigned int code)
-{
- struct key_entry *key;
-
- for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
- if (code == key->code)
- return key;
-
- return NULL;
-}
-
-static struct key_entry *toshiba_acpi_get_entry_by_keycode(unsigned int code)
-{
- struct key_entry *key;
-
- for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
- if (code == key->keycode && key->type == KE_KEY)
- return key;
-
- return NULL;
-}
-
-static int toshiba_acpi_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);
-
- if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int toshiba_acpi_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct key_entry *key;
- unsigned int old_keycode;
-
- key = toshiba_acpi_get_entry_by_scancode(scancode);
- if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!toshiba_acpi_get_entry_by_keycode(old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
- }
-
- return -EINVAL;
-}
-
static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
{
u32 hci_result, value;
- struct key_entry *key;
if (event != 0x80)
return;
@@ -922,19 +860,11 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
if (value & 0x80)
continue;
- key = toshiba_acpi_get_entry_by_scancode
- (value);
- if (!key) {
+ if (!sparse_keymap_report_event(toshiba_acpi.hotkey_dev,
+ value, 1, true)) {
printk(MY_INFO "Unknown key %x\n",
value);
- continue;
}
- input_report_key(toshiba_acpi.hotkey_dev,
- key->keycode, 1);
- input_sync(toshiba_acpi.hotkey_dev);
- input_report_key(toshiba_acpi.hotkey_dev,
- key->keycode, 0);
- input_sync(toshiba_acpi.hotkey_dev);
} else if (hci_result == HCI_NOT_SUPPORTED) {
/* This is a workaround for an unresolved issue on
* some machines where system events sporadically
@@ -945,34 +875,17 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
} while (hci_result != HCI_EMPTY);
}
-static int toshiba_acpi_setup_keyboard(char *device)
+static int __init toshiba_acpi_setup_keyboard(char *device)
{
acpi_status status;
- acpi_handle handle;
- int result;
- const struct key_entry *key;
+ int error;
- status = acpi_get_handle(NULL, device, &handle);
+ status = acpi_get_handle(NULL, device, &toshiba_acpi.handle);
if (ACPI_FAILURE(status)) {
printk(MY_INFO "Unable to get notification device\n");
return -ENODEV;
}
- toshiba_acpi.handle = handle;
-
- status = acpi_evaluate_object(handle, "ENAB", NULL, NULL);
- if (ACPI_FAILURE(status)) {
- printk(MY_INFO "Unable to enable hotkeys\n");
- return -ENODEV;
- }
-
- status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY,
- toshiba_acpi_notify, NULL);
- if (ACPI_FAILURE(status)) {
- printk(MY_INFO "Unable to install hotkey notification\n");
- return -ENODEV;
- }
-
toshiba_acpi.hotkey_dev = input_allocate_device();
if (!toshiba_acpi.hotkey_dev) {
printk(MY_INFO "Unable to register input device\n");
@@ -982,27 +895,54 @@ static int toshiba_acpi_setup_keyboard(char *device)
toshiba_acpi.hotkey_dev->name = "Toshiba input device";
toshiba_acpi.hotkey_dev->phys = device;
toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
- toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode;
- toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode;
- for (key = toshiba_acpi_keymap; key->type != KE_END; key++) {
- set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit);
- set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit);
+ error = sparse_keymap_setup(toshiba_acpi.hotkey_dev,
+ toshiba_acpi_keymap, NULL);
+ if (error)
+ goto err_free_dev;
+
+ status = acpi_install_notify_handler(toshiba_acpi.handle,
+ ACPI_DEVICE_NOTIFY, toshiba_acpi_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "Unable to install hotkey notification\n");
+ error = -ENODEV;
+ goto err_free_keymap;
+ }
+
+ status = acpi_evaluate_object(toshiba_acpi.handle, "ENAB", NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "Unable to enable hotkeys\n");
+ error = -ENODEV;
+ goto err_remove_notify;
}
- result = input_register_device(toshiba_acpi.hotkey_dev);
- if (result) {
+ error = input_register_device(toshiba_acpi.hotkey_dev);
+ if (error) {
printk(MY_INFO "Unable to register input device\n");
- return result;
+ goto err_remove_notify;
}
return 0;
+
+ err_remove_notify:
+ acpi_remove_notify_handler(toshiba_acpi.handle,
+ ACPI_DEVICE_NOTIFY, toshiba_acpi_notify);
+ err_free_keymap:
+ sparse_keymap_free(toshiba_acpi.hotkey_dev);
+ err_free_dev:
+ input_free_device(toshiba_acpi.hotkey_dev);
+ toshiba_acpi.hotkey_dev = NULL;
+ return error;
}
static void toshiba_acpi_exit(void)
{
- if (toshiba_acpi.hotkey_dev)
+ if (toshiba_acpi.hotkey_dev) {
+ acpi_remove_notify_handler(toshiba_acpi.handle,
+ ACPI_DEVICE_NOTIFY, toshiba_acpi_notify);
+ sparse_keymap_free(toshiba_acpi.hotkey_dev);
input_unregister_device(toshiba_acpi.hotkey_dev);
+ }
if (toshiba_acpi.bt_rfk) {
rfkill_unregister(toshiba_acpi.bt_rfk);
@@ -1017,9 +957,6 @@ static void toshiba_acpi_exit(void)
if (toshiba_proc_dir)
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
- acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
- toshiba_acpi_notify);
-
if (toshiba_acpi.illumination_installed)
led_classdev_unregister(&toshiba_led);
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index b2978a04317f..104b77c87ef5 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -27,6 +27,8 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -44,9 +46,8 @@ MODULE_LICENSE("GPL");
#define ACPI_WMI_CLASS "wmi"
-#define PREFIX "ACPI: WMI: "
-
static DEFINE_MUTEX(wmi_data_lock);
+static LIST_HEAD(wmi_block_list);
struct guid_block {
char guid[16];
@@ -67,10 +68,9 @@ struct wmi_block {
acpi_handle handle;
wmi_notify_handler handler;
void *handler_data;
- struct device *dev;
+ struct device dev;
};
-static struct wmi_block wmi_blocks;
/*
* If the GUID data block is marked as expensive, we must enable and
@@ -110,7 +110,7 @@ static struct acpi_driver acpi_wmi_driver = {
.add = acpi_wmi_add,
.remove = acpi_wmi_remove,
.notify = acpi_wmi_notify,
- },
+ },
};
/*
@@ -128,30 +128,18 @@ static struct acpi_driver acpi_wmi_driver = {
*/
static int wmi_parse_hexbyte(const u8 *src)
{
- unsigned int x; /* For correct wrapping */
int h;
+ int value;
/* high part */
- x = src[0];
- if (x - '0' <= '9' - '0') {
- h = x - '0';
- } else if (x - 'a' <= 'f' - 'a') {
- h = x - 'a' + 10;
- } else if (x - 'A' <= 'F' - 'A') {
- h = x - 'A' + 10;
- } else {
+ h = value = hex_to_bin(src[0]);
+ if (value < 0)
return -1;
- }
- h <<= 4;
/* low part */
- x = src[1];
- if (x - '0' <= '9' - '0')
- return h | (x - '0');
- if (x - 'a' <= 'f' - 'a')
- return h | (x - 'a' + 10);
- if (x - 'A' <= 'F' - 'A')
- return h | (x - 'A' + 10);
+ value = hex_to_bin(src[1]);
+ if (value >= 0)
+ return (h << 4) | value;
return -1;
}
@@ -232,7 +220,7 @@ static int wmi_gtoa(const char *in, char *out)
for (i = 10; i <= 15; i++)
out += sprintf(out, "%02X", in[i] & 0xFF);
- out = '\0';
+ *out = '\0';
return 0;
}
@@ -246,7 +234,7 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
wmi_parse_guid(guid_string, tmp);
wmi_swap_bytes(tmp, guid_input);
- list_for_each(p, &wmi_blocks.list) {
+ list_for_each(p, &wmi_block_list) {
wblock = list_entry(p, struct wmi_block, list);
block = &wblock->gblock;
@@ -487,30 +475,29 @@ const struct acpi_buffer *in)
}
EXPORT_SYMBOL_GPL(wmi_set_block);
-static void wmi_dump_wdg(struct guid_block *g)
+static void wmi_dump_wdg(const struct guid_block *g)
{
char guid_string[37];
wmi_gtoa(g->guid, guid_string);
- printk(KERN_INFO PREFIX "%s:\n", guid_string);
- printk(KERN_INFO PREFIX "\tobject_id: %c%c\n",
- g->object_id[0], g->object_id[1]);
- printk(KERN_INFO PREFIX "\tnotify_id: %02X\n", g->notify_id);
- printk(KERN_INFO PREFIX "\treserved: %02X\n", g->reserved);
- printk(KERN_INFO PREFIX "\tinstance_count: %d\n", g->instance_count);
- printk(KERN_INFO PREFIX "\tflags: %#x", g->flags);
+
+ pr_info("%s:\n", guid_string);
+ pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
+ pr_info("\tnotify_id: %02X\n", g->notify_id);
+ pr_info("\treserved: %02X\n", g->reserved);
+ pr_info("\tinstance_count: %d\n", g->instance_count);
+ pr_info("\tflags: %#x ", g->flags);
if (g->flags) {
- printk(" ");
if (g->flags & ACPI_WMI_EXPENSIVE)
- printk("ACPI_WMI_EXPENSIVE ");
+ pr_cont("ACPI_WMI_EXPENSIVE ");
if (g->flags & ACPI_WMI_METHOD)
- printk("ACPI_WMI_METHOD ");
+ pr_cont("ACPI_WMI_METHOD ");
if (g->flags & ACPI_WMI_STRING)
- printk("ACPI_WMI_STRING ");
+ pr_cont("ACPI_WMI_STRING ");
if (g->flags & ACPI_WMI_EVENT)
- printk("ACPI_WMI_EVENT ");
+ pr_cont("ACPI_WMI_EVENT ");
}
- printk("\n");
+ pr_cont("\n");
}
@@ -522,7 +509,7 @@ static void wmi_notify_debug(u32 value, void *context)
status = wmi_get_event_data(value, &response);
if (status != AE_OK) {
- printk(KERN_INFO "wmi: bad event status 0x%x\n", status);
+ pr_info("bad event status 0x%x\n", status);
return;
}
@@ -531,22 +518,22 @@ static void wmi_notify_debug(u32 value, void *context)
if (!obj)
return;
- printk(KERN_INFO PREFIX "DEBUG Event ");
+ pr_info("DEBUG Event ");
switch(obj->type) {
case ACPI_TYPE_BUFFER:
- printk("BUFFER_TYPE - length %d\n", obj->buffer.length);
+ pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
break;
case ACPI_TYPE_STRING:
- printk("STRING_TYPE - %s\n", obj->string.pointer);
+ pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
break;
case ACPI_TYPE_INTEGER:
- printk("INTEGER_TYPE - %llu\n", obj->integer.value);
+ pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
break;
case ACPI_TYPE_PACKAGE:
- printk("PACKAGE_TYPE - %d elements\n", obj->package.count);
+ pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
break;
default:
- printk("object type 0x%X\n", obj->type);
+ pr_cont("object type 0x%X\n", obj->type);
}
kfree(obj);
}
@@ -633,7 +620,7 @@ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
params[0].type = ACPI_TYPE_INTEGER;
params[0].integer.value = event;
- list_for_each(p, &wmi_blocks.list) {
+ list_for_each(p, &wmi_block_list) {
wblock = list_entry(p, struct wmi_block, list);
gblock = &wblock->gblock;
@@ -662,7 +649,7 @@ EXPORT_SYMBOL_GPL(wmi_has_guid);
/*
* sysfs interface
*/
-static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
char guid_string[37];
@@ -676,7 +663,11 @@ static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "wmi:%s\n", guid_string);
}
-static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+
+static struct device_attribute wmi_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL
+};
static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{
@@ -702,108 +693,71 @@ static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
static void wmi_dev_free(struct device *dev)
{
- kfree(dev);
+ struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
+
+ kfree(wmi_block);
}
static struct class wmi_class = {
.name = "wmi",
.dev_release = wmi_dev_free,
.dev_uevent = wmi_dev_uevent,
+ .dev_attrs = wmi_dev_attrs,
};
-static int wmi_create_devs(void)
+static struct wmi_block *wmi_create_device(const struct guid_block *gblock,
+ acpi_handle handle)
{
- int result;
- char guid_string[37];
- struct guid_block *gblock;
struct wmi_block *wblock;
- struct list_head *p;
- struct device *guid_dev;
-
- /* Create devices for all the GUIDs */
- list_for_each(p, &wmi_blocks.list) {
- wblock = list_entry(p, struct wmi_block, list);
-
- guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
- if (!guid_dev)
- return -ENOMEM;
-
- wblock->dev = guid_dev;
-
- guid_dev->class = &wmi_class;
- dev_set_drvdata(guid_dev, wblock);
-
- gblock = &wblock->gblock;
-
- wmi_gtoa(gblock->guid, guid_string);
- dev_set_name(guid_dev, guid_string);
-
- result = device_register(guid_dev);
- if (result)
- return result;
+ int error;
+ char guid_string[37];
- result = device_create_file(guid_dev, &dev_attr_modalias);
- if (result)
- return result;
+ wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
+ if (!wblock) {
+ error = -ENOMEM;
+ goto err_out;
}
- return 0;
-}
+ wblock->handle = handle;
+ wblock->gblock = *gblock;
-static void wmi_remove_devs(void)
-{
- struct guid_block *gblock;
- struct wmi_block *wblock;
- struct list_head *p;
- struct device *guid_dev;
+ wblock->dev.class = &wmi_class;
- /* Delete devices for all the GUIDs */
- list_for_each(p, &wmi_blocks.list) {
- wblock = list_entry(p, struct wmi_block, list);
+ wmi_gtoa(gblock->guid, guid_string);
+ dev_set_name(&wblock->dev, guid_string);
- guid_dev = wblock->dev;
- gblock = &wblock->gblock;
+ dev_set_drvdata(&wblock->dev, wblock);
- device_remove_file(guid_dev, &dev_attr_modalias);
+ error = device_register(&wblock->dev);
+ if (error)
+ goto err_free;
- device_unregister(guid_dev);
- }
-}
+ list_add_tail(&wblock->list, &wmi_block_list);
+ return wblock;
-static void wmi_class_exit(void)
-{
- wmi_remove_devs();
- class_unregister(&wmi_class);
+err_free:
+ kfree(wblock);
+err_out:
+ return ERR_PTR(error);
}
-static int wmi_class_init(void)
+static void wmi_free_devices(void)
{
- int ret;
-
- ret = class_register(&wmi_class);
- if (ret)
- return ret;
+ struct wmi_block *wblock, *next;
- ret = wmi_create_devs();
- if (ret)
- wmi_class_exit();
-
- return ret;
+ /* Delete devices for all the GUIDs */
+ list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
+ device_unregister(&wblock->dev);
}
static bool guid_already_parsed(const char *guid_string)
{
- struct guid_block *gblock;
struct wmi_block *wblock;
- struct list_head *p;
- list_for_each(p, &wmi_blocks.list) {
- wblock = list_entry(p, struct wmi_block, list);
- gblock = &wblock->gblock;
-
- if (strncmp(gblock->guid, guid_string, 16) == 0)
+ list_for_each_entry(wblock, &wmi_block_list, list)
+ if (strncmp(wblock->gblock.guid, guid_string, 16) == 0)
return true;
- }
+
return false;
}
@@ -814,30 +768,29 @@ static acpi_status parse_wdg(acpi_handle handle)
{
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *obj;
- struct guid_block *gblock;
+ const struct guid_block *gblock;
struct wmi_block *wblock;
char guid_string[37];
acpi_status status;
+ int retval;
u32 i, total;
status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
-
if (ACPI_FAILURE(status))
- return status;
+ return -ENXIO;
obj = (union acpi_object *) out.pointer;
+ if (!obj)
+ return -ENXIO;
- if (obj->type != ACPI_TYPE_BUFFER)
- return AE_ERROR;
-
- total = obj->buffer.length / sizeof(struct guid_block);
-
- gblock = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL);
- if (!gblock) {
- status = AE_NO_MEMORY;
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ retval = -ENXIO;
goto out_free_pointer;
}
+ gblock = (const struct guid_block *)obj->buffer.pointer;
+ total = obj->buffer.length / sizeof(struct guid_block);
+
for (i = 0; i < total; i++) {
/*
Some WMI devices, like those for nVidia hooks, have a
@@ -848,34 +801,32 @@ static acpi_status parse_wdg(acpi_handle handle)
*/
if (guid_already_parsed(gblock[i].guid) == true) {
wmi_gtoa(gblock[i].guid, guid_string);
- printk(KERN_INFO PREFIX "Skipping duplicate GUID %s\n",
- guid_string);
+ pr_info("Skipping duplicate GUID %s\n", guid_string);
continue;
}
+
if (debug_dump_wdg)
wmi_dump_wdg(&gblock[i]);
- wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
- if (!wblock) {
- status = AE_NO_MEMORY;
- goto out_free_gblock;
+ wblock = wmi_create_device(&gblock[i], handle);
+ if (IS_ERR(wblock)) {
+ retval = PTR_ERR(wblock);
+ wmi_free_devices();
+ break;
}
- wblock->gblock = gblock[i];
- wblock->handle = handle;
if (debug_event) {
wblock->handler = wmi_notify_debug;
- status = wmi_method_enable(wblock, 1);
+ wmi_method_enable(wblock, 1);
}
- list_add_tail(&wblock->list, &wmi_blocks.list);
}
-out_free_gblock:
- kfree(gblock);
+ retval = 0;
+
out_free_pointer:
kfree(out.pointer);
- return status;
+ return retval;
}
/*
@@ -929,7 +880,7 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event)
struct list_head *p;
char guid_string[37];
- list_for_each(p, &wmi_blocks.list) {
+ list_for_each(p, &wmi_block_list) {
wblock = list_entry(p, struct wmi_block, list);
block = &wblock->gblock;
@@ -939,8 +890,7 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event)
wblock->handler(event, wblock->handler_data);
if (debug_event) {
wmi_gtoa(wblock->gblock.guid, guid_string);
- printk(KERN_INFO PREFIX "DEBUG Event GUID:"
- " %s\n", guid_string);
+ pr_info("DEBUG Event GUID: %s\n", guid_string);
}
acpi_bus_generate_netlink_event(
@@ -955,6 +905,7 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
{
acpi_remove_address_space_handler(device->handle,
ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
+ wmi_free_devices();
return 0;
}
@@ -962,68 +913,57 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
static int acpi_wmi_add(struct acpi_device *device)
{
acpi_status status;
- int result = 0;
+ int error;
status = acpi_install_address_space_handler(device->handle,
ACPI_ADR_SPACE_EC,
&acpi_wmi_ec_space_handler,
NULL, NULL);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- status = parse_wdg(device->handle);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Error installing EC region handler\n");
+ pr_err("Error installing EC region handler\n");
return -ENODEV;
}
- return result;
+ error = parse_wdg(device->handle);
+ if (error) {
+ acpi_remove_address_space_handler(device->handle,
+ ACPI_ADR_SPACE_EC,
+ &acpi_wmi_ec_space_handler);
+ pr_err("Failed to parse WDG method\n");
+ return error;
+ }
+
+ return 0;
}
static int __init acpi_wmi_init(void)
{
- int result;
-
- INIT_LIST_HEAD(&wmi_blocks.list);
+ int error;
if (acpi_disabled)
return -ENODEV;
- result = acpi_bus_register_driver(&acpi_wmi_driver);
+ error = class_register(&wmi_class);
+ if (error)
+ return error;
- if (result < 0) {
- printk(KERN_INFO PREFIX "Error loading mapper\n");
- return -ENODEV;
+ error = acpi_bus_register_driver(&acpi_wmi_driver);
+ if (error) {
+ pr_err("Error loading mapper\n");
+ class_unregister(&wmi_class);
+ return error;
}
- result = wmi_class_init();
- if (result) {
- acpi_bus_unregister_driver(&acpi_wmi_driver);
- return result;
- }
-
- printk(KERN_INFO PREFIX "Mapper loaded\n");
-
- return result;
+ pr_info("Mapper loaded\n");
+ return 0;
}
static void __exit acpi_wmi_exit(void)
{
- struct list_head *p, *tmp;
- struct wmi_block *wblock;
-
- wmi_class_exit();
-
acpi_bus_unregister_driver(&acpi_wmi_driver);
+ class_unregister(&wmi_class);
- list_for_each_safe(p, tmp, &wmi_blocks.list) {
- wblock = list_entry(p, struct wmi_block, list);
-
- list_del(p);
- kfree(wblock);
- }
-
- printk(KERN_INFO PREFIX "Mapper unloaded\n");
+ pr_info("Mapper unloaded\n");
}
subsys_initcall(acpi_wmi_init);
diff --git a/drivers/platform/x86/xo1-rfkill.c b/drivers/platform/x86/xo1-rfkill.c
new file mode 100644
index 000000000000..e549eeeda121
--- /dev/null
+++ b/drivers/platform/x86/xo1-rfkill.c
@@ -0,0 +1,85 @@
+/*
+ * Support for rfkill through the OLPC XO-1 laptop embedded controller
+ *
+ * Copyright (C) 2010 One Laptop per Child
+ *
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+
+#include <asm/olpc.h>
+
+static int rfkill_set_block(void *data, bool blocked)
+{
+ unsigned char cmd;
+ if (blocked)
+ cmd = EC_WLAN_ENTER_RESET;
+ else
+ cmd = EC_WLAN_LEAVE_RESET;
+
+ return olpc_ec_cmd(cmd, NULL, 0, NULL, 0);
+}
+
+static const struct rfkill_ops rfkill_ops = {
+ .set_block = rfkill_set_block,
+};
+
+static int __devinit xo1_rfkill_probe(struct platform_device *pdev)
+{
+ struct rfkill *rfk;
+ int r;
+
+ rfk = rfkill_alloc(pdev->name, &pdev->dev, RFKILL_TYPE_WLAN,
+ &rfkill_ops, NULL);
+ if (!rfk)
+ return -ENOMEM;
+
+ r = rfkill_register(rfk);
+ if (r) {
+ rfkill_destroy(rfk);
+ return r;
+ }
+
+ platform_set_drvdata(pdev, rfk);
+ return 0;
+}
+
+static int __devexit xo1_rfkill_remove(struct platform_device *pdev)
+{
+ struct rfkill *rfk = platform_get_drvdata(pdev);
+ rfkill_unregister(rfk);
+ rfkill_destroy(rfk);
+ return 0;
+}
+
+static struct platform_driver xo1_rfkill_driver = {
+ .driver = {
+ .name = "xo1-rfkill",
+ .owner = THIS_MODULE,
+ },
+ .probe = xo1_rfkill_probe,
+ .remove = __devexit_p(xo1_rfkill_remove),
+};
+
+static int __init xo1_rfkill_init(void)
+{
+ return platform_driver_register(&xo1_rfkill_driver);
+}
+
+static void __exit xo1_rfkill_exit(void)
+{
+ platform_driver_unregister(&xo1_rfkill_driver);
+}
+
+MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:xo1-rfkill");
+
+module_init(xo1_rfkill_init);
+module_exit(xo1_rfkill_exit);
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index 13f48e28a1e1..a624f5af4320 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -461,7 +461,7 @@ static int jsflash_init(void)
{
int rc;
struct jsflash *jsf;
- int node;
+ phandle node;
char banner[128];
struct linux_prom_registers reg0;
diff --git a/drivers/serial/68328serial.h b/drivers/serial/68328serial.h
index 58aa2154655b..664ceb0a158c 100644
--- a/drivers/serial/68328serial.h
+++ b/drivers/serial/68328serial.h
@@ -181,13 +181,8 @@ struct m68k_serial {
/*
* Define the number of ports supported and their irqs.
*/
-#ifndef CONFIG_68328_SERIAL_UART2
#define NR_PORTS 1
#define UART_IRQ_DEFNS {UART_IRQ_NUM}
-#else
-#define NR_PORTS 2
-#define UART_IRQ_DEFNS {UART1_IRQ_NUM, UART2_IRQ_NUM}
-#endif
#endif /* __KERNEL__ */
#endif /* !(_MC683XX_SERIAL_H) */
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index 2af8fd113123..17849dcb9adc 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -31,8 +31,8 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
{
struct resource resource;
struct device_node *np = ofdev->dev.of_node;
- const unsigned int *clk, *spd;
- const u32 *prop;
+ const __be32 *clk, *spd;
+ const __be32 *prop;
int ret, prop_size;
memset(port, 0, sizeof *port);
@@ -55,23 +55,23 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
/* Check for shifted address mapping */
prop = of_get_property(np, "reg-offset", &prop_size);
if (prop && (prop_size == sizeof(u32)))
- port->mapbase += *prop;
+ port->mapbase += be32_to_cpup(prop);
/* Check for registers offset within the devices address range */
prop = of_get_property(np, "reg-shift", &prop_size);
if (prop && (prop_size == sizeof(u32)))
- port->regshift = *prop;
+ port->regshift = be32_to_cpup(prop);
port->irq = irq_of_parse_and_map(np, 0);
port->iotype = UPIO_MEM;
port->type = type;
- port->uartclk = *clk;
+ port->uartclk = be32_to_cpup(clk);
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
port->dev = &ofdev->dev;
/* If current-speed was set, then try not to change it. */
if (spd)
- port->custom_divisor = *clk / (16 * (*spd));
+ port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd)));
return 0;
}
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 9b52f77a9305..d2352ac437c5 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -140,7 +140,15 @@
# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
# define SCSPTR1 0xffe10024 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* Overrun error bit */
-# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+
+#if defined(CONFIG_SH_SH2007)
+/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */
+# define SCSCR_INIT(port) 0x38
+#else
+/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */
+# define SCSCR_INIT(port) 0x3a
+#endif
+
#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
defined(CONFIG_CPU_SUBTYPE_SH7786)
# define SCSPTR0 0xffea0024 /* 16 bit SCIF */
@@ -616,9 +624,10 @@ static inline int sci_rxd_in(struct uart_port *port)
* -- Mitch Davis - 15 Jul 2000
*/
-#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
- defined(CONFIG_CPU_SUBTYPE_SH7785) || \
- defined(CONFIG_CPU_SUBTYPE_SH7786)
+#if (defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7786)) && \
+ !defined(CONFIG_SH_SH2007)
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
diff --git a/drivers/sh/Kconfig b/drivers/sh/Kconfig
index a54de0b9b3df..f168a6159961 100644
--- a/drivers/sh/Kconfig
+++ b/drivers/sh/Kconfig
@@ -1,24 +1,5 @@
-config INTC_USERIMASK
- bool "Userspace interrupt masking support"
- depends on ARCH_SHMOBILE || (SUPERH && CPU_SH4A)
- help
- This enables support for hardware-assisted userspace hardirq
- masking.
+menu "SuperH / SH-Mobile Driver Options"
- SH-4A and newer interrupt blocks all support a special shadowed
- page with all non-masking registers obscured when mapped in to
- userspace. This is primarily for use by userspace device
- drivers that are using special priority levels.
+source "drivers/sh/intc/Kconfig"
- If in doubt, say N.
-
-config INTC_BALANCING
- bool "Hardware IRQ balancing support"
- depends on SMP && SUPERH && CPU_SUBTYPE_SH7786
- help
- This enables support for IRQ auto-distribution mode on SH-X3
- SMP parts. All of the balancing and CPU wakeup decisions are
- taken care of automatically by hardware for distributed
- vectors.
-
- If in doubt, say N.
+endmenu
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index 08fc653a825c..24e6cec0ae8d 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -1,10 +1,9 @@
#
# Makefile for the SuperH specific drivers.
#
-obj-y := clk.o intc.o
+obj-y := intc/
-obj-$(CONFIG_SUPERHYWAY) += superhyway/
+obj-$(CONFIG_HAVE_CLK) += clk/
obj-$(CONFIG_MAPLE) += maple/
-
+obj-$(CONFIG_SUPERHYWAY) += superhyway/
obj-$(CONFIG_GENERIC_GPIO) += pfc.o
-obj-$(CONFIG_SH_CLK_CPG) += clk-cpg.o
diff --git a/drivers/sh/clk/Makefile b/drivers/sh/clk/Makefile
new file mode 100644
index 000000000000..5d15ebfaa074
--- /dev/null
+++ b/drivers/sh/clk/Makefile
@@ -0,0 +1,3 @@
+obj-y := core.o
+
+obj-$(CONFIG_SH_CLK_CPG) += cpg.o
diff --git a/drivers/sh/clk.c b/drivers/sh/clk/core.c
index 5d84adac9ec4..fd0d1b98901c 100644
--- a/drivers/sh/clk.c
+++ b/drivers/sh/clk/core.c
@@ -1,7 +1,7 @@
/*
- * drivers/sh/clk.c - SuperH clock framework
+ * SuperH clock framework
*
- * Copyright (C) 2005 - 2009 Paul Mundt
+ * Copyright (C) 2005 - 2010 Paul Mundt
*
* This clock framework is derived from the OMAP version by:
*
@@ -14,6 +14,8 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#define pr_fmt(fmt) "clock: " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -23,7 +25,7 @@
#include <linux/sysdev.h>
#include <linux/seq_file.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/io.h>
#include <linux/debugfs.h>
#include <linux/cpufreq.h>
#include <linux/clk.h>
@@ -43,6 +45,8 @@ void clk_rate_table_build(struct clk *clk,
unsigned long freq;
int i;
+ clk->nr_freqs = nr_freqs;
+
for (i = 0; i < nr_freqs; i++) {
div = 1;
mult = 1;
@@ -67,29 +71,39 @@ void clk_rate_table_build(struct clk *clk,
freq_table[i].frequency = CPUFREQ_TABLE_END;
}
-long clk_rate_table_round(struct clk *clk,
- struct cpufreq_frequency_table *freq_table,
- unsigned long rate)
+struct clk_rate_round_data;
+
+struct clk_rate_round_data {
+ unsigned long rate;
+ unsigned int min, max;
+ long (*func)(unsigned int, struct clk_rate_round_data *);
+ void *arg;
+};
+
+#define for_each_frequency(pos, r, freq) \
+ for (pos = r->min, freq = r->func(pos, r); \
+ pos <= r->max; pos++, freq = r->func(pos, r)) \
+ if (unlikely(freq == 0)) \
+ ; \
+ else
+
+static long clk_rate_round_helper(struct clk_rate_round_data *rounder)
{
unsigned long rate_error, rate_error_prev = ~0UL;
- unsigned long rate_best_fit = rate;
- unsigned long highest, lowest;
+ unsigned long rate_best_fit = rounder->rate;
+ unsigned long highest, lowest, freq;
int i;
- highest = lowest = 0;
-
- for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
- unsigned long freq = freq_table[i].frequency;
-
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
+ highest = 0;
+ lowest = ~0UL;
+ for_each_frequency(i, rounder, freq) {
if (freq > highest)
highest = freq;
if (freq < lowest)
lowest = freq;
- rate_error = abs(freq - rate);
+ rate_error = abs(freq - rounder->rate);
if (rate_error < rate_error_prev) {
rate_best_fit = freq;
rate_error_prev = rate_error;
@@ -99,14 +113,64 @@ long clk_rate_table_round(struct clk *clk,
break;
}
- if (rate >= highest)
+ if (rounder->rate >= highest)
rate_best_fit = highest;
- if (rate <= lowest)
+ if (rounder->rate <= lowest)
rate_best_fit = lowest;
return rate_best_fit;
}
+static long clk_rate_table_iter(unsigned int pos,
+ struct clk_rate_round_data *rounder)
+{
+ struct cpufreq_frequency_table *freq_table = rounder->arg;
+ unsigned long freq = freq_table[pos].frequency;
+
+ if (freq == CPUFREQ_ENTRY_INVALID)
+ freq = 0;
+
+ return freq;
+}
+
+long clk_rate_table_round(struct clk *clk,
+ struct cpufreq_frequency_table *freq_table,
+ unsigned long rate)
+{
+ struct clk_rate_round_data table_round = {
+ .min = 0,
+ .max = clk->nr_freqs - 1,
+ .func = clk_rate_table_iter,
+ .arg = freq_table,
+ .rate = rate,
+ };
+
+ if (clk->nr_freqs < 1)
+ return 0;
+
+ return clk_rate_round_helper(&table_round);
+}
+
+static long clk_rate_div_range_iter(unsigned int pos,
+ struct clk_rate_round_data *rounder)
+{
+ return clk_get_rate(rounder->arg) / pos;
+}
+
+long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
+ unsigned int div_max, unsigned long rate)
+{
+ struct clk_rate_round_data div_range_round = {
+ .min = div_min,
+ .max = div_max,
+ .func = clk_rate_div_range_iter,
+ .arg = clk_get_parent(clk),
+ .rate = rate,
+ };
+
+ return clk_rate_round_helper(&div_range_round);
+}
+
int clk_rate_table_find(struct clk *clk,
struct cpufreq_frequency_table *freq_table,
unsigned long rate)
@@ -160,8 +224,8 @@ void propagate_rate(struct clk *tclk)
static void __clk_disable(struct clk *clk)
{
- if (WARN(!clk->usecount, "Trying to disable clock %s with 0 usecount\n",
- clk->name))
+ if (WARN(!clk->usecount, "Trying to disable clock %p with 0 usecount\n",
+ clk))
return;
if (!(--clk->usecount)) {
@@ -248,8 +312,88 @@ void recalculate_root_clocks(void)
}
}
+static struct clk_mapping dummy_mapping;
+
+static struct clk *lookup_root_clock(struct clk *clk)
+{
+ while (clk->parent)
+ clk = clk->parent;
+
+ return clk;
+}
+
+static int clk_establish_mapping(struct clk *clk)
+{
+ struct clk_mapping *mapping = clk->mapping;
+
+ /*
+ * Propagate mappings.
+ */
+ if (!mapping) {
+ struct clk *clkp;
+
+ /*
+ * dummy mapping for root clocks with no specified ranges
+ */
+ if (!clk->parent) {
+ clk->mapping = &dummy_mapping;
+ return 0;
+ }
+
+ /*
+ * If we're on a child clock and it provides no mapping of its
+ * own, inherit the mapping from its root clock.
+ */
+ clkp = lookup_root_clock(clk);
+ mapping = clkp->mapping;
+ BUG_ON(!mapping);
+ }
+
+ /*
+ * Establish initial mapping.
+ */
+ if (!mapping->base && mapping->phys) {
+ kref_init(&mapping->ref);
+
+ mapping->base = ioremap_nocache(mapping->phys, mapping->len);
+ if (unlikely(!mapping->base))
+ return -ENXIO;
+ } else if (mapping->base) {
+ /*
+ * Bump the refcount for an existing mapping
+ */
+ kref_get(&mapping->ref);
+ }
+
+ clk->mapping = mapping;
+ return 0;
+}
+
+static void clk_destroy_mapping(struct kref *kref)
+{
+ struct clk_mapping *mapping;
+
+ mapping = container_of(kref, struct clk_mapping, ref);
+
+ iounmap(mapping->base);
+}
+
+static void clk_teardown_mapping(struct clk *clk)
+{
+ struct clk_mapping *mapping = clk->mapping;
+
+ /* Nothing to do */
+ if (mapping == &dummy_mapping)
+ return;
+
+ kref_put(&mapping->ref, clk_destroy_mapping);
+ clk->mapping = NULL;
+}
+
int clk_register(struct clk *clk)
{
+ int ret;
+
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
@@ -264,6 +408,10 @@ int clk_register(struct clk *clk)
INIT_LIST_HEAD(&clk->children);
clk->usecount = 0;
+ ret = clk_establish_mapping(clk);
+ if (unlikely(ret))
+ goto out_unlock;
+
if (clk->parent)
list_add(&clk->sibling, &clk->parent->children);
else
@@ -272,9 +420,11 @@ int clk_register(struct clk *clk)
list_add(&clk->node, &clock_list);
if (clk->ops && clk->ops->init)
clk->ops->init(clk);
+
+out_unlock:
mutex_unlock(&clock_list_sem);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(clk_register);
@@ -283,6 +433,7 @@ void clk_unregister(struct clk *clk)
mutex_lock(&clock_list_sem);
list_del(&clk->sibling);
list_del(&clk->node);
+ clk_teardown_mapping(clk);
mutex_unlock(&clock_list_sem);
}
EXPORT_SYMBOL_GPL(clk_unregister);
@@ -354,10 +505,10 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
ret = clk_reparent(clk, parent);
if (ret == 0) {
- pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
- clk->name, clk->parent->name, clk->rate);
if (clk->ops->recalc)
clk->rate = clk->ops->recalc(clk);
+ pr_debug("set parent of %p to %p (new rate %ld)\n",
+ clk, clk->parent, clk->rate);
propagate_rate(clk);
}
} else
@@ -469,9 +620,7 @@ static int clk_debugfs_register_one(struct clk *c)
char s[255];
char *p = s;
- p += sprintf(p, "%s", c->name);
- if (c->id >= 0)
- sprintf(p, ":%d", c->id);
+ p += sprintf(p, "%p", c);
d = debugfs_create_dir(s, pa ? pa->dentry : clk_debugfs_root);
if (!d)
return -ENOMEM;
@@ -513,7 +662,7 @@ static int clk_debugfs_register(struct clk *c)
return err;
}
- if (!c->dentry && c->name) {
+ if (!c->dentry) {
err = clk_debugfs_register_one(c);
if (err)
return err;
diff --git a/drivers/sh/clk-cpg.c b/drivers/sh/clk/cpg.c
index 8c024b984ed8..3aea5f0ceb09 100644
--- a/drivers/sh/clk-cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -1,3 +1,12 @@
+/*
+ * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
+ *
+ * Copyright (C) 2010 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/slab.h>
@@ -180,7 +189,6 @@ static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
clkp = clks + k;
clkp->ops = ops;
- clkp->id = -1;
clkp->freq_table = freq_table + (k * freq_table_size);
clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
@@ -319,7 +327,6 @@ static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
clkp = clks + k;
clkp->ops = ops;
- clkp->id = -1;
clkp->priv = table;
clkp->freq_table = freq_table + (k * freq_table_size);
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
deleted file mode 100644
index e91a23e5ffd8..000000000000
--- a/drivers/sh/intc.c
+++ /dev/null
@@ -1,1390 +0,0 @@
-/*
- * Shared interrupt handling code for IPR and INTC2 types of IRQs.
- *
- * Copyright (C) 2007, 2008 Magnus Damm
- * Copyright (C) 2009, 2010 Paul Mundt
- *
- * Based on intc2.c and ipr.c
- *
- * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
- * Copyright (C) 2000 Kazumoto Kojima
- * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
- * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
- * Copyright (C) 2005, 2006 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/sh_intc.h>
-#include <linux/sysdev.h>
-#include <linux/list.h>
-#include <linux/topology.h>
-#include <linux/bitmap.h>
-#include <linux/cpumask.h>
-#include <asm/sizes.h>
-
-#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
- ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
- ((addr_e) << 16) | ((addr_d << 24)))
-
-#define _INTC_SHIFT(h) (h & 0x1f)
-#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
-#define _INTC_FN(h) ((h >> 9) & 0xf)
-#define _INTC_MODE(h) ((h >> 13) & 0x7)
-#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
-#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)
-
-struct intc_handle_int {
- unsigned int irq;
- unsigned long handle;
-};
-
-struct intc_window {
- phys_addr_t phys;
- void __iomem *virt;
- unsigned long size;
-};
-
-struct intc_desc_int {
- struct list_head list;
- struct sys_device sysdev;
- pm_message_t state;
- unsigned long *reg;
-#ifdef CONFIG_SMP
- unsigned long *smp;
-#endif
- unsigned int nr_reg;
- struct intc_handle_int *prio;
- unsigned int nr_prio;
- struct intc_handle_int *sense;
- unsigned int nr_sense;
- struct intc_window *window;
- unsigned int nr_windows;
- struct irq_chip chip;
-};
-
-static LIST_HEAD(intc_list);
-
-/*
- * The intc_irq_map provides a global map of bound IRQ vectors for a
- * given platform. Allocation of IRQs are either static through the CPU
- * vector map, or dynamic in the case of board mux vectors or MSI.
- *
- * As this is a central point for all IRQ controllers on the system,
- * each of the available sources are mapped out here. This combined with
- * sparseirq makes it quite trivial to keep the vector map tightly packed
- * when dynamically creating IRQs, as well as tying in to otherwise
- * unused irq_desc positions in the sparse array.
- */
-static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
-static DEFINE_SPINLOCK(vector_lock);
-
-#ifdef CONFIG_SMP
-#define IS_SMP(x) x.smp
-#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
-#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
-#else
-#define IS_SMP(x) 0
-#define INTC_REG(d, x, c) (d->reg[(x)])
-#define SMP_NR(d, x) 1
-#endif
-
-static unsigned int intc_prio_level[NR_IRQS]; /* for now */
-static unsigned int default_prio_level = 2; /* 2 - 16 */
-static unsigned long ack_handle[NR_IRQS];
-#ifdef CONFIG_INTC_BALANCING
-static unsigned long dist_handle[NR_IRQS];
-#endif
-
-static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
-{
- struct irq_chip *chip = get_irq_chip(irq);
- return container_of(chip, struct intc_desc_int, chip);
-}
-
-static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
- unsigned long address)
-{
- struct intc_window *window;
- int k;
-
- /* scan through physical windows and convert address */
- for (k = 0; k < d->nr_windows; k++) {
- window = d->window + k;
-
- if (address < window->phys)
- continue;
-
- if (address >= (window->phys + window->size))
- continue;
-
- address -= window->phys;
- address += (unsigned long)window->virt;
-
- return address;
- }
-
- /* no windows defined, register must be 1:1 mapped virt:phys */
- return address;
-}
-
-static unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
-{
- unsigned int k;
-
- address = intc_phys_to_virt(d, address);
-
- for (k = 0; k < d->nr_reg; k++) {
- if (d->reg[k] == address)
- return k;
- }
-
- BUG();
- return 0;
-}
-
-static inline unsigned int set_field(unsigned int value,
- unsigned int field_value,
- unsigned int handle)
-{
- unsigned int width = _INTC_WIDTH(handle);
- unsigned int shift = _INTC_SHIFT(handle);
-
- value &= ~(((1 << width) - 1) << shift);
- value |= field_value << shift;
- return value;
-}
-
-static void write_8(unsigned long addr, unsigned long h, unsigned long data)
-{
- __raw_writeb(set_field(0, data, h), addr);
- (void)__raw_readb(addr); /* Defeat write posting */
-}
-
-static void write_16(unsigned long addr, unsigned long h, unsigned long data)
-{
- __raw_writew(set_field(0, data, h), addr);
- (void)__raw_readw(addr); /* Defeat write posting */
-}
-
-static void write_32(unsigned long addr, unsigned long h, unsigned long data)
-{
- __raw_writel(set_field(0, data, h), addr);
- (void)__raw_readl(addr); /* Defeat write posting */
-}
-
-static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
-{
- unsigned long flags;
- local_irq_save(flags);
- __raw_writeb(set_field(__raw_readb(addr), data, h), addr);
- (void)__raw_readb(addr); /* Defeat write posting */
- local_irq_restore(flags);
-}
-
-static void modify_16(unsigned long addr, unsigned long h, unsigned long data)
-{
- unsigned long flags;
- local_irq_save(flags);
- __raw_writew(set_field(__raw_readw(addr), data, h), addr);
- (void)__raw_readw(addr); /* Defeat write posting */
- local_irq_restore(flags);
-}
-
-static void modify_32(unsigned long addr, unsigned long h, unsigned long data)
-{
- unsigned long flags;
- local_irq_save(flags);
- __raw_writel(set_field(__raw_readl(addr), data, h), addr);
- (void)__raw_readl(addr); /* Defeat write posting */
- local_irq_restore(flags);
-}
-
-enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 };
-
-static void (*intc_reg_fns[])(unsigned long addr,
- unsigned long h,
- unsigned long data) = {
- [REG_FN_WRITE_BASE + 0] = write_8,
- [REG_FN_WRITE_BASE + 1] = write_16,
- [REG_FN_WRITE_BASE + 3] = write_32,
- [REG_FN_MODIFY_BASE + 0] = modify_8,
- [REG_FN_MODIFY_BASE + 1] = modify_16,
- [REG_FN_MODIFY_BASE + 3] = modify_32,
-};
-
-enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
- MODE_MASK_REG, /* Bit(s) set -> interrupt disabled */
- MODE_DUAL_REG, /* Two registers, set bit to enable / disable */
- MODE_PRIO_REG, /* Priority value written to enable interrupt */
- MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */
-};
-
-static void intc_mode_field(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq)
-{
- fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
-}
-
-static void intc_mode_zero(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq)
-{
- fn(addr, handle, 0);
-}
-
-static void intc_mode_prio(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq)
-{
- fn(addr, handle, intc_prio_level[irq]);
-}
-
-static void (*intc_enable_fns[])(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq) = {
- [MODE_ENABLE_REG] = intc_mode_field,
- [MODE_MASK_REG] = intc_mode_zero,
- [MODE_DUAL_REG] = intc_mode_field,
- [MODE_PRIO_REG] = intc_mode_prio,
- [MODE_PCLR_REG] = intc_mode_prio,
-};
-
-static void (*intc_disable_fns[])(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq) = {
- [MODE_ENABLE_REG] = intc_mode_zero,
- [MODE_MASK_REG] = intc_mode_field,
- [MODE_DUAL_REG] = intc_mode_field,
- [MODE_PRIO_REG] = intc_mode_zero,
- [MODE_PCLR_REG] = intc_mode_field,
-};
-
-#ifdef CONFIG_INTC_BALANCING
-static inline void intc_balancing_enable(unsigned int irq)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long handle = dist_handle[irq];
- unsigned long addr;
-
- if (irq_balancing_disabled(irq) || !handle)
- return;
-
- addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
- intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
-}
-
-static inline void intc_balancing_disable(unsigned int irq)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long handle = dist_handle[irq];
- unsigned long addr;
-
- if (irq_balancing_disabled(irq) || !handle)
- return;
-
- addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
- intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
-}
-
-static unsigned int intc_dist_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id)
-{
- struct intc_mask_reg *mr = desc->hw.mask_regs;
- unsigned int i, j, fn, mode;
- unsigned long reg_e, reg_d;
-
- for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
- mr = desc->hw.mask_regs + i;
-
- /*
- * Skip this entry if there's no auto-distribution
- * register associated with it.
- */
- if (!mr->dist_reg)
- continue;
-
- for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
- if (mr->enum_ids[j] != enum_id)
- continue;
-
- fn = REG_FN_MODIFY_BASE;
- mode = MODE_ENABLE_REG;
- reg_e = mr->dist_reg;
- reg_d = mr->dist_reg;
-
- fn += (mr->reg_width >> 3) - 1;
- return _INTC_MK(fn, mode,
- intc_get_reg(d, reg_e),
- intc_get_reg(d, reg_d),
- 1,
- (mr->reg_width - 1) - j);
- }
- }
-
- /*
- * It's possible we've gotten here with no distribution options
- * available for the IRQ in question, so we just skip over those.
- */
- return 0;
-}
-#else
-static inline void intc_balancing_enable(unsigned int irq)
-{
-}
-
-static inline void intc_balancing_disable(unsigned int irq)
-{
-}
-#endif
-
-static inline void _intc_enable(unsigned int irq, unsigned long handle)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long addr;
- unsigned int cpu;
-
- for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
-#ifdef CONFIG_SMP
- if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
- continue;
-#endif
- addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
- intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
- [_INTC_FN(handle)], irq);
- }
-
- intc_balancing_enable(irq);
-}
-
-static void intc_enable(unsigned int irq)
-{
- _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
-}
-
-static void intc_disable(unsigned int irq)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long handle = (unsigned long)get_irq_chip_data(irq);
- unsigned long addr;
- unsigned int cpu;
-
- intc_balancing_disable(irq);
-
- for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
-#ifdef CONFIG_SMP
- if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
- continue;
-#endif
- addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
- intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
- [_INTC_FN(handle)], irq);
- }
-}
-
-static void (*intc_enable_noprio_fns[])(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq) = {
- [MODE_ENABLE_REG] = intc_mode_field,
- [MODE_MASK_REG] = intc_mode_zero,
- [MODE_DUAL_REG] = intc_mode_field,
- [MODE_PRIO_REG] = intc_mode_field,
- [MODE_PCLR_REG] = intc_mode_field,
-};
-
-static void intc_enable_disable(struct intc_desc_int *d,
- unsigned long handle, int do_enable)
-{
- unsigned long addr;
- unsigned int cpu;
- void (*fn)(unsigned long, unsigned long,
- void (*)(unsigned long, unsigned long, unsigned long),
- unsigned int);
-
- if (do_enable) {
- for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
- addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
- fn = intc_enable_noprio_fns[_INTC_MODE(handle)];
- fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
- }
- } else {
- for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
- addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
- fn = intc_disable_fns[_INTC_MODE(handle)];
- fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
- }
- }
-}
-
-static int intc_set_wake(unsigned int irq, unsigned int on)
-{
- return 0; /* allow wakeup, but setup hardware in intc_suspend() */
-}
-
-#ifdef CONFIG_SMP
-/*
- * This is held with the irq desc lock held, so we don't require any
- * additional locking here at the intc desc level. The affinity mask is
- * later tested in the enable/disable paths.
- */
-static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask)
-{
- if (!cpumask_intersects(cpumask, cpu_online_mask))
- return -1;
-
- cpumask_copy(irq_to_desc(irq)->affinity, cpumask);
-
- return 0;
-}
-#endif
-
-static void intc_mask_ack(unsigned int irq)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long handle = ack_handle[irq];
- unsigned long addr;
-
- intc_disable(irq);
-
- /* read register and write zero only to the associated bit */
- if (handle) {
- addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
- switch (_INTC_FN(handle)) {
- case REG_FN_MODIFY_BASE + 0: /* 8bit */
- __raw_readb(addr);
- __raw_writeb(0xff ^ set_field(0, 1, handle), addr);
- break;
- case REG_FN_MODIFY_BASE + 1: /* 16bit */
- __raw_readw(addr);
- __raw_writew(0xffff ^ set_field(0, 1, handle), addr);
- break;
- case REG_FN_MODIFY_BASE + 3: /* 32bit */
- __raw_readl(addr);
- __raw_writel(0xffffffff ^ set_field(0, 1, handle), addr);
- break;
- default:
- BUG();
- break;
- }
- }
-}
-
-static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
- unsigned int nr_hp,
- unsigned int irq)
-{
- int i;
-
- /*
- * this doesn't scale well, but...
- *
- * this function should only be used for cerain uncommon
- * operations such as intc_set_priority() and intc_set_sense()
- * and in those rare cases performance doesn't matter that much.
- * keeping the memory footprint low is more important.
- *
- * one rather simple way to speed this up and still keep the
- * memory footprint down is to make sure the array is sorted
- * and then perform a bisect to lookup the irq.
- */
- for (i = 0; i < nr_hp; i++) {
- if ((hp + i)->irq != irq)
- continue;
-
- return hp + i;
- }
-
- return NULL;
-}
-
-int intc_set_priority(unsigned int irq, unsigned int prio)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- struct intc_handle_int *ihp;
-
- if (!intc_prio_level[irq] || prio <= 1)
- return -EINVAL;
-
- ihp = intc_find_irq(d->prio, d->nr_prio, irq);
- if (ihp) {
- if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
- return -EINVAL;
-
- intc_prio_level[irq] = prio;
-
- /*
- * only set secondary masking method directly
- * primary masking method is using intc_prio_level[irq]
- * priority level will be set during next enable()
- */
- if (_INTC_FN(ihp->handle) != REG_FN_ERR)
- _intc_enable(irq, ihp->handle);
- }
- return 0;
-}
-
-#define VALID(x) (x | 0x80)
-
-static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
- [IRQ_TYPE_EDGE_FALLING] = VALID(0),
- [IRQ_TYPE_EDGE_RISING] = VALID(1),
- [IRQ_TYPE_LEVEL_LOW] = VALID(2),
- /* SH7706, SH7707 and SH7709 do not support high level triggered */
-#if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
- !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
- !defined(CONFIG_CPU_SUBTYPE_SH7709)
- [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
-#endif
-};
-
-static int intc_set_sense(unsigned int irq, unsigned int type)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
- struct intc_handle_int *ihp;
- unsigned long addr;
-
- if (!value)
- return -EINVAL;
-
- ihp = intc_find_irq(d->sense, d->nr_sense, irq);
- if (ihp) {
- addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
- intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
- }
- return 0;
-}
-
-static intc_enum __init intc_grp_id(struct intc_desc *desc,
- intc_enum enum_id)
-{
- struct intc_group *g = desc->hw.groups;
- unsigned int i, j;
-
- for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) {
- g = desc->hw.groups + i;
-
- for (j = 0; g->enum_ids[j]; j++) {
- if (g->enum_ids[j] != enum_id)
- continue;
-
- return g->enum_id;
- }
- }
-
- return 0;
-}
-
-static unsigned int __init _intc_mask_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id,
- unsigned int *reg_idx,
- unsigned int *fld_idx)
-{
- struct intc_mask_reg *mr = desc->hw.mask_regs;
- unsigned int fn, mode;
- unsigned long reg_e, reg_d;
-
- while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) {
- mr = desc->hw.mask_regs + *reg_idx;
-
- for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) {
- if (mr->enum_ids[*fld_idx] != enum_id)
- continue;
-
- if (mr->set_reg && mr->clr_reg) {
- fn = REG_FN_WRITE_BASE;
- mode = MODE_DUAL_REG;
- reg_e = mr->clr_reg;
- reg_d = mr->set_reg;
- } else {
- fn = REG_FN_MODIFY_BASE;
- if (mr->set_reg) {
- mode = MODE_ENABLE_REG;
- reg_e = mr->set_reg;
- reg_d = mr->set_reg;
- } else {
- mode = MODE_MASK_REG;
- reg_e = mr->clr_reg;
- reg_d = mr->clr_reg;
- }
- }
-
- fn += (mr->reg_width >> 3) - 1;
- return _INTC_MK(fn, mode,
- intc_get_reg(d, reg_e),
- intc_get_reg(d, reg_d),
- 1,
- (mr->reg_width - 1) - *fld_idx);
- }
-
- *fld_idx = 0;
- (*reg_idx)++;
- }
-
- return 0;
-}
-
-static unsigned int __init intc_mask_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id, int do_grps)
-{
- unsigned int i = 0;
- unsigned int j = 0;
- unsigned int ret;
-
- ret = _intc_mask_data(desc, d, enum_id, &i, &j);
- if (ret)
- return ret;
-
- if (do_grps)
- return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
-
- return 0;
-}
-
-static unsigned int __init _intc_prio_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id,
- unsigned int *reg_idx,
- unsigned int *fld_idx)
-{
- struct intc_prio_reg *pr = desc->hw.prio_regs;
- unsigned int fn, n, mode, bit;
- unsigned long reg_e, reg_d;
-
- while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) {
- pr = desc->hw.prio_regs + *reg_idx;
-
- for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) {
- if (pr->enum_ids[*fld_idx] != enum_id)
- continue;
-
- if (pr->set_reg && pr->clr_reg) {
- fn = REG_FN_WRITE_BASE;
- mode = MODE_PCLR_REG;
- reg_e = pr->set_reg;
- reg_d = pr->clr_reg;
- } else {
- fn = REG_FN_MODIFY_BASE;
- mode = MODE_PRIO_REG;
- if (!pr->set_reg)
- BUG();
- reg_e = pr->set_reg;
- reg_d = pr->set_reg;
- }
-
- fn += (pr->reg_width >> 3) - 1;
- n = *fld_idx + 1;
-
- BUG_ON(n * pr->field_width > pr->reg_width);
-
- bit = pr->reg_width - (n * pr->field_width);
-
- return _INTC_MK(fn, mode,
- intc_get_reg(d, reg_e),
- intc_get_reg(d, reg_d),
- pr->field_width, bit);
- }
-
- *fld_idx = 0;
- (*reg_idx)++;
- }
-
- return 0;
-}
-
-static unsigned int __init intc_prio_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id, int do_grps)
-{
- unsigned int i = 0;
- unsigned int j = 0;
- unsigned int ret;
-
- ret = _intc_prio_data(desc, d, enum_id, &i, &j);
- if (ret)
- return ret;
-
- if (do_grps)
- return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);
-
- return 0;
-}
-
-static void __init intc_enable_disable_enum(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id, int enable)
-{
- unsigned int i, j, data;
-
- /* go through and enable/disable all mask bits */
- i = j = 0;
- do {
- data = _intc_mask_data(desc, d, enum_id, &i, &j);
- if (data)
- intc_enable_disable(d, data, enable);
- j++;
- } while (data);
-
- /* go through and enable/disable all priority fields */
- i = j = 0;
- do {
- data = _intc_prio_data(desc, d, enum_id, &i, &j);
- if (data)
- intc_enable_disable(d, data, enable);
-
- j++;
- } while (data);
-}
-
-static unsigned int __init intc_ack_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id)
-{
- struct intc_mask_reg *mr = desc->hw.ack_regs;
- unsigned int i, j, fn, mode;
- unsigned long reg_e, reg_d;
-
- for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) {
- mr = desc->hw.ack_regs + i;
-
- for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
- if (mr->enum_ids[j] != enum_id)
- continue;
-
- fn = REG_FN_MODIFY_BASE;
- mode = MODE_ENABLE_REG;
- reg_e = mr->set_reg;
- reg_d = mr->set_reg;
-
- fn += (mr->reg_width >> 3) - 1;
- return _INTC_MK(fn, mode,
- intc_get_reg(d, reg_e),
- intc_get_reg(d, reg_d),
- 1,
- (mr->reg_width - 1) - j);
- }
- }
-
- return 0;
-}
-
-static unsigned int __init intc_sense_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id)
-{
- struct intc_sense_reg *sr = desc->hw.sense_regs;
- unsigned int i, j, fn, bit;
-
- for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) {
- sr = desc->hw.sense_regs + i;
-
- for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
- if (sr->enum_ids[j] != enum_id)
- continue;
-
- fn = REG_FN_MODIFY_BASE;
- fn += (sr->reg_width >> 3) - 1;
-
- BUG_ON((j + 1) * sr->field_width > sr->reg_width);
-
- bit = sr->reg_width - ((j + 1) * sr->field_width);
-
- return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
- 0, sr->field_width, bit);
- }
- }
-
- return 0;
-}
-
-static void __init intc_register_irq(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id,
- unsigned int irq)
-{
- struct intc_handle_int *hp;
- unsigned int data[2], primary;
-
- /*
- * Register the IRQ position with the global IRQ map
- */
- set_bit(irq, intc_irq_map);
-
- /*
- * Prefer single interrupt source bitmap over other combinations:
- *
- * 1. bitmap, single interrupt source
- * 2. priority, single interrupt source
- * 3. bitmap, multiple interrupt sources (groups)
- * 4. priority, multiple interrupt sources (groups)
- */
- data[0] = intc_mask_data(desc, d, enum_id, 0);
- data[1] = intc_prio_data(desc, d, enum_id, 0);
-
- primary = 0;
- if (!data[0] && data[1])
- primary = 1;
-
- if (!data[0] && !data[1])
- pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n",
- irq, irq2evt(irq));
-
- data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
- data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
-
- if (!data[primary])
- primary ^= 1;
-
- BUG_ON(!data[primary]); /* must have primary masking method */
-
- disable_irq_nosync(irq);
- set_irq_chip_and_handler_name(irq, &d->chip,
- handle_level_irq, "level");
- set_irq_chip_data(irq, (void *)data[primary]);
-
- /*
- * set priority level
- * - this needs to be at least 2 for 5-bit priorities on 7780
- */
- intc_prio_level[irq] = default_prio_level;
-
- /* enable secondary masking method if present */
- if (data[!primary])
- _intc_enable(irq, data[!primary]);
-
- /* add irq to d->prio list if priority is available */
- if (data[1]) {
- hp = d->prio + d->nr_prio;
- hp->irq = irq;
- hp->handle = data[1];
-
- if (primary) {
- /*
- * only secondary priority should access registers, so
- * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
- */
- hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
- hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
- }
- d->nr_prio++;
- }
-
- /* add irq to d->sense list if sense is available */
- data[0] = intc_sense_data(desc, d, enum_id);
- if (data[0]) {
- (d->sense + d->nr_sense)->irq = irq;
- (d->sense + d->nr_sense)->handle = data[0];
- d->nr_sense++;
- }
-
- /* irq should be disabled by default */
- d->chip.mask(irq);
-
- if (desc->hw.ack_regs)
- ack_handle[irq] = intc_ack_data(desc, d, enum_id);
-
-#ifdef CONFIG_INTC_BALANCING
- if (desc->hw.mask_regs)
- dist_handle[irq] = intc_dist_data(desc, d, enum_id);
-#endif
-
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
-#endif
-}
-
-static unsigned int __init save_reg(struct intc_desc_int *d,
- unsigned int cnt,
- unsigned long value,
- unsigned int smp)
-{
- if (value) {
- value = intc_phys_to_virt(d, value);
-
- d->reg[cnt] = value;
-#ifdef CONFIG_SMP
- d->smp[cnt] = smp;
-#endif
- return 1;
- }
-
- return 0;
-}
-
-static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
-{
- generic_handle_irq((unsigned int)get_irq_data(irq));
-}
-
-int __init register_intc_controller(struct intc_desc *desc)
-{
- unsigned int i, k, smp;
- struct intc_hw_desc *hw = &desc->hw;
- struct intc_desc_int *d;
- struct resource *res;
-
- pr_info("Registered controller '%s' with %u IRQs\n",
- desc->name, hw->nr_vectors);
-
- d = kzalloc(sizeof(*d), GFP_NOWAIT);
- if (!d)
- goto err0;
-
- INIT_LIST_HEAD(&d->list);
- list_add(&d->list, &intc_list);
-
- if (desc->num_resources) {
- d->nr_windows = desc->num_resources;
- d->window = kzalloc(d->nr_windows * sizeof(*d->window),
- GFP_NOWAIT);
- if (!d->window)
- goto err1;
-
- for (k = 0; k < d->nr_windows; k++) {
- res = desc->resource + k;
- WARN_ON(resource_type(res) != IORESOURCE_MEM);
- d->window[k].phys = res->start;
- d->window[k].size = resource_size(res);
- d->window[k].virt = ioremap_nocache(res->start,
- resource_size(res));
- if (!d->window[k].virt)
- goto err2;
- }
- }
-
- d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
-#ifdef CONFIG_INTC_BALANCING
- if (d->nr_reg)
- d->nr_reg += hw->nr_mask_regs;
-#endif
- d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
- d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
- d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
-
- d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
- if (!d->reg)
- goto err2;
-
-#ifdef CONFIG_SMP
- d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
- if (!d->smp)
- goto err3;
-#endif
- k = 0;
-
- if (hw->mask_regs) {
- for (i = 0; i < hw->nr_mask_regs; i++) {
- smp = IS_SMP(hw->mask_regs[i]);
- k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
- k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
-#ifdef CONFIG_INTC_BALANCING
- k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0);
-#endif
- }
- }
-
- if (hw->prio_regs) {
- d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
- GFP_NOWAIT);
- if (!d->prio)
- goto err4;
-
- for (i = 0; i < hw->nr_prio_regs; i++) {
- smp = IS_SMP(hw->prio_regs[i]);
- k += save_reg(d, k, hw->prio_regs[i].set_reg, smp);
- k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp);
- }
- }
-
- if (hw->sense_regs) {
- d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
- GFP_NOWAIT);
- if (!d->sense)
- goto err5;
-
- for (i = 0; i < hw->nr_sense_regs; i++)
- k += save_reg(d, k, hw->sense_regs[i].reg, 0);
- }
-
- d->chip.name = desc->name;
- d->chip.mask = intc_disable;
- d->chip.unmask = intc_enable;
- d->chip.mask_ack = intc_disable;
- d->chip.enable = intc_enable;
- d->chip.disable = intc_disable;
- d->chip.shutdown = intc_disable;
- d->chip.set_type = intc_set_sense;
- d->chip.set_wake = intc_set_wake;
-#ifdef CONFIG_SMP
- d->chip.set_affinity = intc_set_affinity;
-#endif
-
- if (hw->ack_regs) {
- for (i = 0; i < hw->nr_ack_regs; i++)
- k += save_reg(d, k, hw->ack_regs[i].set_reg, 0);
-
- d->chip.mask_ack = intc_mask_ack;
- }
-
- /* disable bits matching force_disable before registering irqs */
- if (desc->force_disable)
- intc_enable_disable_enum(desc, d, desc->force_disable, 0);
-
- /* disable bits matching force_enable before registering irqs */
- if (desc->force_enable)
- intc_enable_disable_enum(desc, d, desc->force_enable, 0);
-
- BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
-
- /* register the vectors one by one */
- for (i = 0; i < hw->nr_vectors; i++) {
- struct intc_vect *vect = hw->vectors + i;
- unsigned int irq = evt2irq(vect->vect);
- struct irq_desc *irq_desc;
-
- if (!vect->enum_id)
- continue;
-
- irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
- if (unlikely(!irq_desc)) {
- pr_err("can't get irq_desc for %d\n", irq);
- continue;
- }
-
- intc_register_irq(desc, d, vect->enum_id, irq);
-
- for (k = i + 1; k < hw->nr_vectors; k++) {
- struct intc_vect *vect2 = hw->vectors + k;
- unsigned int irq2 = evt2irq(vect2->vect);
-
- if (vect->enum_id != vect2->enum_id)
- continue;
-
- /*
- * In the case of multi-evt handling and sparse
- * IRQ support, each vector still needs to have
- * its own backing irq_desc.
- */
- irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id());
- if (unlikely(!irq_desc)) {
- pr_err("can't get irq_desc for %d\n", irq2);
- continue;
- }
-
- vect2->enum_id = 0;
-
- /* redirect this interrupts to the first one */
- set_irq_chip(irq2, &dummy_irq_chip);
- set_irq_chained_handler(irq2, intc_redirect_irq);
- set_irq_data(irq2, (void *)irq);
- }
- }
-
- /* enable bits matching force_enable after registering irqs */
- if (desc->force_enable)
- intc_enable_disable_enum(desc, d, desc->force_enable, 1);
-
- return 0;
-err5:
- kfree(d->prio);
-err4:
-#ifdef CONFIG_SMP
- kfree(d->smp);
-err3:
-#endif
- kfree(d->reg);
-err2:
- for (k = 0; k < d->nr_windows; k++)
- if (d->window[k].virt)
- iounmap(d->window[k].virt);
-
- kfree(d->window);
-err1:
- kfree(d);
-err0:
- pr_err("unable to allocate INTC memory\n");
-
- return -ENOMEM;
-}
-
-#ifdef CONFIG_INTC_USERIMASK
-static void __iomem *uimask;
-
-int register_intc_userimask(unsigned long addr)
-{
- if (unlikely(uimask))
- return -EBUSY;
-
- uimask = ioremap_nocache(addr, SZ_4K);
- if (unlikely(!uimask))
- return -ENOMEM;
-
- pr_info("userimask support registered for levels 0 -> %d\n",
- default_prio_level - 1);
-
- return 0;
-}
-
-static ssize_t
-show_intc_userimask(struct sysdev_class *cls,
- struct sysdev_class_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf);
-}
-
-static ssize_t
-store_intc_userimask(struct sysdev_class *cls,
- struct sysdev_class_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned long level;
-
- level = simple_strtoul(buf, NULL, 10);
-
- /*
- * Minimal acceptable IRQ levels are in the 2 - 16 range, but
- * these are chomped so as to not interfere with normal IRQs.
- *
- * Level 1 is a special case on some CPUs in that it's not
- * directly settable, but given that USERIMASK cuts off below a
- * certain level, we don't care about this limitation here.
- * Level 0 on the other hand equates to user masking disabled.
- *
- * We use default_prio_level as a cut off so that only special
- * case opt-in IRQs can be mangled.
- */
- if (level >= default_prio_level)
- return -EINVAL;
-
- __raw_writel(0xa5 << 24 | level << 4, uimask);
-
- return count;
-}
-
-static SYSDEV_CLASS_ATTR(userimask, S_IRUSR | S_IWUSR,
- show_intc_userimask, store_intc_userimask);
-#endif
-
-static ssize_t
-show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
-{
- struct intc_desc_int *d;
-
- d = container_of(dev, struct intc_desc_int, sysdev);
-
- return sprintf(buf, "%s\n", d->chip.name);
-}
-
-static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
-
-static int intc_suspend(struct sys_device *dev, pm_message_t state)
-{
- struct intc_desc_int *d;
- struct irq_desc *desc;
- int irq;
-
- /* get intc controller associated with this sysdev */
- d = container_of(dev, struct intc_desc_int, sysdev);
-
- switch (state.event) {
- case PM_EVENT_ON:
- if (d->state.event != PM_EVENT_FREEZE)
- break;
- for_each_irq_desc(irq, desc) {
- if (desc->handle_irq == intc_redirect_irq)
- continue;
- if (desc->chip != &d->chip)
- continue;
- if (desc->status & IRQ_DISABLED)
- intc_disable(irq);
- else
- intc_enable(irq);
- }
- break;
- case PM_EVENT_FREEZE:
- /* nothing has to be done */
- break;
- case PM_EVENT_SUSPEND:
- /* enable wakeup irqs belonging to this intc controller */
- for_each_irq_desc(irq, desc) {
- if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip))
- intc_enable(irq);
- }
- break;
- }
- d->state = state;
-
- return 0;
-}
-
-static int intc_resume(struct sys_device *dev)
-{
- return intc_suspend(dev, PMSG_ON);
-}
-
-static struct sysdev_class intc_sysdev_class = {
- .name = "intc",
- .suspend = intc_suspend,
- .resume = intc_resume,
-};
-
-/* register this intc as sysdev to allow suspend/resume */
-static int __init register_intc_sysdevs(void)
-{
- struct intc_desc_int *d;
- int error;
- int id = 0;
-
- error = sysdev_class_register(&intc_sysdev_class);
-#ifdef CONFIG_INTC_USERIMASK
- if (!error && uimask)
- error = sysdev_class_create_file(&intc_sysdev_class,
- &attr_userimask);
-#endif
- if (!error) {
- list_for_each_entry(d, &intc_list, list) {
- d->sysdev.id = id;
- d->sysdev.cls = &intc_sysdev_class;
- error = sysdev_register(&d->sysdev);
- if (error == 0)
- error = sysdev_create_file(&d->sysdev,
- &attr_name);
- if (error)
- break;
-
- id++;
- }
- }
-
- if (error)
- pr_err("sysdev registration error\n");
-
- return error;
-}
-device_initcall(register_intc_sysdevs);
-
-/*
- * Dynamic IRQ allocation and deallocation
- */
-unsigned int create_irq_nr(unsigned int irq_want, int node)
-{
- unsigned int irq = 0, new;
- unsigned long flags;
- struct irq_desc *desc;
-
- spin_lock_irqsave(&vector_lock, flags);
-
- /*
- * First try the wanted IRQ
- */
- if (test_and_set_bit(irq_want, intc_irq_map) == 0) {
- new = irq_want;
- } else {
- /* .. then fall back to scanning. */
- new = find_first_zero_bit(intc_irq_map, nr_irqs);
- if (unlikely(new == nr_irqs))
- goto out_unlock;
-
- __set_bit(new, intc_irq_map);
- }
-
- desc = irq_to_desc_alloc_node(new, node);
- if (unlikely(!desc)) {
- pr_err("can't get irq_desc for %d\n", new);
- goto out_unlock;
- }
-
- desc = move_irq_desc(desc, node);
- irq = new;
-
-out_unlock:
- spin_unlock_irqrestore(&vector_lock, flags);
-
- if (irq > 0) {
- dynamic_irq_init(irq);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
-#endif
- }
-
- return irq;
-}
-
-int create_irq(void)
-{
- int nid = cpu_to_node(smp_processor_id());
- int irq;
-
- irq = create_irq_nr(NR_IRQS_LEGACY, nid);
- if (irq == 0)
- irq = -1;
-
- return irq;
-}
-
-void destroy_irq(unsigned int irq)
-{
- unsigned long flags;
-
- dynamic_irq_cleanup(irq);
-
- spin_lock_irqsave(&vector_lock, flags);
- __clear_bit(irq, intc_irq_map);
- spin_unlock_irqrestore(&vector_lock, flags);
-}
-
-int reserve_irq_vector(unsigned int irq)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&vector_lock, flags);
- if (test_and_set_bit(irq, intc_irq_map))
- ret = -EBUSY;
- spin_unlock_irqrestore(&vector_lock, flags);
-
- return ret;
-}
-
-void reserve_irq_legacy(void)
-{
- unsigned long flags;
- int i, j;
-
- spin_lock_irqsave(&vector_lock, flags);
- j = find_first_bit(intc_irq_map, nr_irqs);
- for (i = 0; i < j; i++)
- __set_bit(i, intc_irq_map);
- spin_unlock_irqrestore(&vector_lock, flags);
-}
diff --git a/drivers/sh/intc/Kconfig b/drivers/sh/intc/Kconfig
new file mode 100644
index 000000000000..c88cbccc62b0
--- /dev/null
+++ b/drivers/sh/intc/Kconfig
@@ -0,0 +1,35 @@
+comment "Interrupt controller options"
+
+config INTC_USERIMASK
+ bool "Userspace interrupt masking support"
+ depends on ARCH_SHMOBILE || (SUPERH && CPU_SH4A)
+ help
+ This enables support for hardware-assisted userspace hardirq
+ masking.
+
+ SH-4A and newer interrupt blocks all support a special shadowed
+ page with all non-masking registers obscured when mapped in to
+ userspace. This is primarily for use by userspace device
+ drivers that are using special priority levels.
+
+ If in doubt, say N.
+
+config INTC_BALANCING
+ bool "Hardware IRQ balancing support"
+ depends on SMP && SUPERH && CPU_SHX3
+ help
+ This enables support for IRQ auto-distribution mode on SH-X3
+ SMP parts. All of the balancing and CPU wakeup decisions are
+ taken care of automatically by hardware for distributed
+ vectors.
+
+ If in doubt, say N.
+
+config INTC_MAPPING_DEBUG
+ bool "Expose IRQ to per-controller id mapping via debugfs"
+ depends on DEBUG_FS
+ help
+ This will create a debugfs entry for showing the relationship
+ between system IRQs and the per-controller id tables.
+
+ If in doubt, say N.
diff --git a/drivers/sh/intc/Makefile b/drivers/sh/intc/Makefile
new file mode 100644
index 000000000000..bb5df868d77a
--- /dev/null
+++ b/drivers/sh/intc/Makefile
@@ -0,0 +1,5 @@
+obj-y := access.o chip.o core.o dynamic.o handle.o virq.o
+
+obj-$(CONFIG_INTC_BALANCING) += balancing.o
+obj-$(CONFIG_INTC_USERIMASK) += userimask.o
+obj-$(CONFIG_INTC_MAPPING_DEBUG) += virq-debugfs.o
diff --git a/drivers/sh/intc/access.c b/drivers/sh/intc/access.c
new file mode 100644
index 000000000000..f892ae1d212a
--- /dev/null
+++ b/drivers/sh/intc/access.c
@@ -0,0 +1,237 @@
+/*
+ * Common INTC2 register accessors
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/io.h>
+#include "internals.h"
+
+unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
+{
+ struct intc_window *window;
+ int k;
+
+ /* scan through physical windows and convert address */
+ for (k = 0; k < d->nr_windows; k++) {
+ window = d->window + k;
+
+ if (address < window->phys)
+ continue;
+
+ if (address >= (window->phys + window->size))
+ continue;
+
+ address -= window->phys;
+ address += (unsigned long)window->virt;
+
+ return address;
+ }
+
+ /* no windows defined, register must be 1:1 mapped virt:phys */
+ return address;
+}
+
+unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
+{
+ unsigned int k;
+
+ address = intc_phys_to_virt(d, address);
+
+ for (k = 0; k < d->nr_reg; k++) {
+ if (d->reg[k] == address)
+ return k;
+ }
+
+ BUG();
+ return 0;
+}
+
+unsigned int intc_set_field_from_handle(unsigned int value,
+ unsigned int field_value,
+ unsigned int handle)
+{
+ unsigned int width = _INTC_WIDTH(handle);
+ unsigned int shift = _INTC_SHIFT(handle);
+
+ value &= ~(((1 << width) - 1) << shift);
+ value |= field_value << shift;
+ return value;
+}
+
+unsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
+{
+ unsigned int width = _INTC_WIDTH(handle);
+ unsigned int shift = _INTC_SHIFT(handle);
+ unsigned int mask = ((1 << width) - 1) << shift;
+
+ return (value & mask) >> shift;
+}
+
+static unsigned long test_8(unsigned long addr, unsigned long h,
+ unsigned long ignore)
+{
+ return intc_get_field_from_handle(__raw_readb(addr), h);
+}
+
+static unsigned long test_16(unsigned long addr, unsigned long h,
+ unsigned long ignore)
+{
+ return intc_get_field_from_handle(__raw_readw(addr), h);
+}
+
+static unsigned long test_32(unsigned long addr, unsigned long h,
+ unsigned long ignore)
+{
+ return intc_get_field_from_handle(__raw_readl(addr), h);
+}
+
+static unsigned long write_8(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ __raw_writeb(intc_set_field_from_handle(0, data, h), addr);
+ (void)__raw_readb(addr); /* Defeat write posting */
+ return 0;
+}
+
+static unsigned long write_16(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ __raw_writew(intc_set_field_from_handle(0, data, h), addr);
+ (void)__raw_readw(addr); /* Defeat write posting */
+ return 0;
+}
+
+static unsigned long write_32(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ __raw_writel(intc_set_field_from_handle(0, data, h), addr);
+ (void)__raw_readl(addr); /* Defeat write posting */
+ return 0;
+}
+
+static unsigned long modify_8(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ unsigned long flags;
+ unsigned int value;
+ local_irq_save(flags);
+ value = intc_set_field_from_handle(__raw_readb(addr), data, h);
+ __raw_writeb(value, addr);
+ (void)__raw_readb(addr); /* Defeat write posting */
+ local_irq_restore(flags);
+ return 0;
+}
+
+static unsigned long modify_16(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ unsigned long flags;
+ unsigned int value;
+ local_irq_save(flags);
+ value = intc_set_field_from_handle(__raw_readw(addr), data, h);
+ __raw_writew(value, addr);
+ (void)__raw_readw(addr); /* Defeat write posting */
+ local_irq_restore(flags);
+ return 0;
+}
+
+static unsigned long modify_32(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ unsigned long flags;
+ unsigned int value;
+ local_irq_save(flags);
+ value = intc_set_field_from_handle(__raw_readl(addr), data, h);
+ __raw_writel(value, addr);
+ (void)__raw_readl(addr); /* Defeat write posting */
+ local_irq_restore(flags);
+ return 0;
+}
+
+static unsigned long intc_mode_field(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
+{
+ return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
+}
+
+static unsigned long intc_mode_zero(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
+{
+ return fn(addr, handle, 0);
+}
+
+static unsigned long intc_mode_prio(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
+{
+ return fn(addr, handle, intc_get_prio_level(irq));
+}
+
+unsigned long (*intc_reg_fns[])(unsigned long addr,
+ unsigned long h,
+ unsigned long data) = {
+ [REG_FN_TEST_BASE + 0] = test_8,
+ [REG_FN_TEST_BASE + 1] = test_16,
+ [REG_FN_TEST_BASE + 3] = test_32,
+ [REG_FN_WRITE_BASE + 0] = write_8,
+ [REG_FN_WRITE_BASE + 1] = write_16,
+ [REG_FN_WRITE_BASE + 3] = write_32,
+ [REG_FN_MODIFY_BASE + 0] = modify_8,
+ [REG_FN_MODIFY_BASE + 1] = modify_16,
+ [REG_FN_MODIFY_BASE + 3] = modify_32,
+};
+
+unsigned long (*intc_enable_fns[])(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_field,
+ [MODE_MASK_REG] = intc_mode_zero,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_prio,
+ [MODE_PCLR_REG] = intc_mode_prio,
+};
+
+unsigned long (*intc_disable_fns[])(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_zero,
+ [MODE_MASK_REG] = intc_mode_field,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_zero,
+ [MODE_PCLR_REG] = intc_mode_field,
+};
+
+unsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_field,
+ [MODE_MASK_REG] = intc_mode_zero,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_field,
+ [MODE_PCLR_REG] = intc_mode_field,
+};
diff --git a/drivers/sh/intc/balancing.c b/drivers/sh/intc/balancing.c
new file mode 100644
index 000000000000..cec7a96f2c09
--- /dev/null
+++ b/drivers/sh/intc/balancing.c
@@ -0,0 +1,97 @@
+/*
+ * Support for hardware-managed IRQ auto-distribution.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include "internals.h"
+
+static unsigned long dist_handle[NR_IRQS];
+
+void intc_balancing_enable(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = dist_handle[irq];
+ unsigned long addr;
+
+ if (irq_balancing_disabled(irq) || !handle)
+ return;
+
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+ intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
+}
+
+void intc_balancing_disable(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = dist_handle[irq];
+ unsigned long addr;
+
+ if (irq_balancing_disabled(irq) || !handle)
+ return;
+
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+ intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
+}
+
+static unsigned int intc_dist_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id)
+{
+ struct intc_mask_reg *mr = desc->hw.mask_regs;
+ unsigned int i, j, fn, mode;
+ unsigned long reg_e, reg_d;
+
+ for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
+ mr = desc->hw.mask_regs + i;
+
+ /*
+ * Skip this entry if there's no auto-distribution
+ * register associated with it.
+ */
+ if (!mr->dist_reg)
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+ if (mr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = REG_FN_MODIFY_BASE;
+ mode = MODE_ENABLE_REG;
+ reg_e = mr->dist_reg;
+ reg_d = mr->dist_reg;
+
+ fn += (mr->reg_width >> 3) - 1;
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ 1,
+ (mr->reg_width - 1) - j);
+ }
+ }
+
+ /*
+ * It's possible we've gotten here with no distribution options
+ * available for the IRQ in question, so we just skip over those.
+ */
+ return 0;
+}
+
+void intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
+ struct intc_desc_int *d, intc_enum id)
+{
+ unsigned long flags;
+
+ /*
+ * Nothing to do for this IRQ.
+ */
+ if (!desc->hw.mask_regs)
+ return;
+
+ raw_spin_lock_irqsave(&intc_big_lock, flags);
+ dist_handle[irq] = intc_dist_data(desc, d, id);
+ raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c
new file mode 100644
index 000000000000..35c03706cc21
--- /dev/null
+++ b/drivers/sh/intc/chip.c
@@ -0,0 +1,215 @@
+/*
+ * IRQ chip definitions for INTC IRQs.
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/cpumask.h>
+#include <linux/io.h>
+#include "internals.h"
+
+void _intc_enable(unsigned int irq, unsigned long handle)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long addr;
+ unsigned int cpu;
+
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+#ifdef CONFIG_SMP
+ if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
+ continue;
+#endif
+ addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+ intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
+ [_INTC_FN(handle)], irq);
+ }
+
+ intc_balancing_enable(irq);
+}
+
+static void intc_enable(unsigned int irq)
+{
+ _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
+}
+
+static void intc_disable(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = (unsigned long)get_irq_chip_data(irq);
+ unsigned long addr;
+ unsigned int cpu;
+
+ intc_balancing_disable(irq);
+
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+#ifdef CONFIG_SMP
+ if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
+ continue;
+#endif
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+ intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
+ [_INTC_FN(handle)], irq);
+ }
+}
+
+static int intc_set_wake(unsigned int irq, unsigned int on)
+{
+ return 0; /* allow wakeup, but setup hardware in intc_suspend() */
+}
+
+#ifdef CONFIG_SMP
+/*
+ * This is held with the irq desc lock held, so we don't require any
+ * additional locking here at the intc desc level. The affinity mask is
+ * later tested in the enable/disable paths.
+ */
+static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+{
+ if (!cpumask_intersects(cpumask, cpu_online_mask))
+ return -1;
+
+ cpumask_copy(irq_to_desc(irq)->affinity, cpumask);
+
+ return 0;
+}
+#endif
+
+static void intc_mask_ack(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = intc_get_ack_handle(irq);
+ unsigned long addr;
+
+ intc_disable(irq);
+
+ /* read register and write zero only to the associated bit */
+ if (handle) {
+ unsigned int value;
+
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+ value = intc_set_field_from_handle(0, 1, handle);
+
+ switch (_INTC_FN(handle)) {
+ case REG_FN_MODIFY_BASE + 0: /* 8bit */
+ __raw_readb(addr);
+ __raw_writeb(0xff ^ value, addr);
+ break;
+ case REG_FN_MODIFY_BASE + 1: /* 16bit */
+ __raw_readw(addr);
+ __raw_writew(0xffff ^ value, addr);
+ break;
+ case REG_FN_MODIFY_BASE + 3: /* 32bit */
+ __raw_readl(addr);
+ __raw_writel(0xffffffff ^ value, addr);
+ break;
+ default:
+ BUG();
+ break;
+ }
+ }
+}
+
+static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
+ unsigned int nr_hp,
+ unsigned int irq)
+{
+ int i;
+
+ /*
+ * this doesn't scale well, but...
+ *
+ * this function should only be used for cerain uncommon
+ * operations such as intc_set_priority() and intc_set_type()
+ * and in those rare cases performance doesn't matter that much.
+ * keeping the memory footprint low is more important.
+ *
+ * one rather simple way to speed this up and still keep the
+ * memory footprint down is to make sure the array is sorted
+ * and then perform a bisect to lookup the irq.
+ */
+ for (i = 0; i < nr_hp; i++) {
+ if ((hp + i)->irq != irq)
+ continue;
+
+ return hp + i;
+ }
+
+ return NULL;
+}
+
+int intc_set_priority(unsigned int irq, unsigned int prio)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ struct intc_handle_int *ihp;
+
+ if (!intc_get_prio_level(irq) || prio <= 1)
+ return -EINVAL;
+
+ ihp = intc_find_irq(d->prio, d->nr_prio, irq);
+ if (ihp) {
+ if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
+ return -EINVAL;
+
+ intc_set_prio_level(irq, prio);
+
+ /*
+ * only set secondary masking method directly
+ * primary masking method is using intc_prio_level[irq]
+ * priority level will be set during next enable()
+ */
+ if (_INTC_FN(ihp->handle) != REG_FN_ERR)
+ _intc_enable(irq, ihp->handle);
+ }
+ return 0;
+}
+
+#define VALID(x) (x | 0x80)
+
+static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+ [IRQ_TYPE_EDGE_FALLING] = VALID(0),
+ [IRQ_TYPE_EDGE_RISING] = VALID(1),
+ [IRQ_TYPE_LEVEL_LOW] = VALID(2),
+ /* SH7706, SH7707 and SH7709 do not support high level triggered */
+#if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7709)
+ [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
+#endif
+};
+
+static int intc_set_type(unsigned int irq, unsigned int type)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
+ struct intc_handle_int *ihp;
+ unsigned long addr;
+
+ if (!value)
+ return -EINVAL;
+
+ ihp = intc_find_irq(d->sense, d->nr_sense, irq);
+ if (ihp) {
+ addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
+ intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
+ }
+
+ return 0;
+}
+
+struct irq_chip intc_irq_chip = {
+ .mask = intc_disable,
+ .unmask = intc_enable,
+ .mask_ack = intc_mask_ack,
+ .enable = intc_enable,
+ .disable = intc_disable,
+ .shutdown = intc_disable,
+ .set_type = intc_set_type,
+ .set_wake = intc_set_wake,
+#ifdef CONFIG_SMP
+ .set_affinity = intc_set_affinity,
+#endif
+};
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
new file mode 100644
index 000000000000..306ed287077a
--- /dev/null
+++ b/drivers/sh/intc/core.c
@@ -0,0 +1,469 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * Based on intc2.c and ipr.c
+ *
+ * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
+ * Copyright (C) 2000 Kazumoto Kojima
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Copyright (C) 2005, 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/sh_intc.h>
+#include <linux/sysdev.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/radix-tree.h>
+#include "internals.h"
+
+LIST_HEAD(intc_list);
+DEFINE_RAW_SPINLOCK(intc_big_lock);
+unsigned int nr_intc_controllers;
+
+/*
+ * Default priority level
+ * - this needs to be at least 2 for 5-bit priorities on 7780
+ */
+static unsigned int default_prio_level = 2; /* 2 - 16 */
+static unsigned int intc_prio_level[NR_IRQS]; /* for now */
+
+unsigned int intc_get_dfl_prio_level(void)
+{
+ return default_prio_level;
+}
+
+unsigned int intc_get_prio_level(unsigned int irq)
+{
+ return intc_prio_level[irq];
+}
+
+void intc_set_prio_level(unsigned int irq, unsigned int level)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&intc_big_lock, flags);
+ intc_prio_level[irq] = level;
+ raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
+
+static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
+{
+ generic_handle_irq((unsigned int)get_irq_data(irq));
+}
+
+static void __init intc_register_irq(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id,
+ unsigned int irq)
+{
+ struct intc_handle_int *hp;
+ unsigned int data[2], primary;
+ unsigned long flags;
+
+ /*
+ * Register the IRQ position with the global IRQ map, then insert
+ * it in to the radix tree.
+ */
+ reserve_irq_vector(irq);
+
+ raw_spin_lock_irqsave(&intc_big_lock, flags);
+ radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
+ raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+
+ /*
+ * Prefer single interrupt source bitmap over other combinations:
+ *
+ * 1. bitmap, single interrupt source
+ * 2. priority, single interrupt source
+ * 3. bitmap, multiple interrupt sources (groups)
+ * 4. priority, multiple interrupt sources (groups)
+ */
+ data[0] = intc_get_mask_handle(desc, d, enum_id, 0);
+ data[1] = intc_get_prio_handle(desc, d, enum_id, 0);
+
+ primary = 0;
+ if (!data[0] && data[1])
+ primary = 1;
+
+ if (!data[0] && !data[1])
+ pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n",
+ irq, irq2evt(irq));
+
+ data[0] = data[0] ? data[0] : intc_get_mask_handle(desc, d, enum_id, 1);
+ data[1] = data[1] ? data[1] : intc_get_prio_handle(desc, d, enum_id, 1);
+
+ if (!data[primary])
+ primary ^= 1;
+
+ BUG_ON(!data[primary]); /* must have primary masking method */
+
+ disable_irq_nosync(irq);
+ set_irq_chip_and_handler_name(irq, &d->chip,
+ handle_level_irq, "level");
+ set_irq_chip_data(irq, (void *)data[primary]);
+
+ /*
+ * set priority level
+ */
+ intc_set_prio_level(irq, intc_get_dfl_prio_level());
+
+ /* enable secondary masking method if present */
+ if (data[!primary])
+ _intc_enable(irq, data[!primary]);
+
+ /* add irq to d->prio list if priority is available */
+ if (data[1]) {
+ hp = d->prio + d->nr_prio;
+ hp->irq = irq;
+ hp->handle = data[1];
+
+ if (primary) {
+ /*
+ * only secondary priority should access registers, so
+ * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
+ */
+ hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
+ hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
+ }
+ d->nr_prio++;
+ }
+
+ /* add irq to d->sense list if sense is available */
+ data[0] = intc_get_sense_handle(desc, d, enum_id);
+ if (data[0]) {
+ (d->sense + d->nr_sense)->irq = irq;
+ (d->sense + d->nr_sense)->handle = data[0];
+ d->nr_sense++;
+ }
+
+ /* irq should be disabled by default */
+ d->chip.mask(irq);
+
+ intc_set_ack_handle(irq, desc, d, enum_id);
+ intc_set_dist_handle(irq, desc, d, enum_id);
+
+ activate_irq(irq);
+}
+
+static unsigned int __init save_reg(struct intc_desc_int *d,
+ unsigned int cnt,
+ unsigned long value,
+ unsigned int smp)
+{
+ if (value) {
+ value = intc_phys_to_virt(d, value);
+
+ d->reg[cnt] = value;
+#ifdef CONFIG_SMP
+ d->smp[cnt] = smp;
+#endif
+ return 1;
+ }
+
+ return 0;
+}
+
+int __init register_intc_controller(struct intc_desc *desc)
+{
+ unsigned int i, k, smp;
+ struct intc_hw_desc *hw = &desc->hw;
+ struct intc_desc_int *d;
+ struct resource *res;
+
+ pr_info("Registered controller '%s' with %u IRQs\n",
+ desc->name, hw->nr_vectors);
+
+ d = kzalloc(sizeof(*d), GFP_NOWAIT);
+ if (!d)
+ goto err0;
+
+ INIT_LIST_HEAD(&d->list);
+ list_add_tail(&d->list, &intc_list);
+
+ raw_spin_lock_init(&d->lock);
+
+ d->index = nr_intc_controllers;
+
+ if (desc->num_resources) {
+ d->nr_windows = desc->num_resources;
+ d->window = kzalloc(d->nr_windows * sizeof(*d->window),
+ GFP_NOWAIT);
+ if (!d->window)
+ goto err1;
+
+ for (k = 0; k < d->nr_windows; k++) {
+ res = desc->resource + k;
+ WARN_ON(resource_type(res) != IORESOURCE_MEM);
+ d->window[k].phys = res->start;
+ d->window[k].size = resource_size(res);
+ d->window[k].virt = ioremap_nocache(res->start,
+ resource_size(res));
+ if (!d->window[k].virt)
+ goto err2;
+ }
+ }
+
+ d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
+#ifdef CONFIG_INTC_BALANCING
+ if (d->nr_reg)
+ d->nr_reg += hw->nr_mask_regs;
+#endif
+ d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
+ d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
+ d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
+ d->nr_reg += hw->subgroups ? hw->nr_subgroups : 0;
+
+ d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
+ if (!d->reg)
+ goto err2;
+
+#ifdef CONFIG_SMP
+ d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
+ if (!d->smp)
+ goto err3;
+#endif
+ k = 0;
+
+ if (hw->mask_regs) {
+ for (i = 0; i < hw->nr_mask_regs; i++) {
+ smp = IS_SMP(hw->mask_regs[i]);
+ k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
+ k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
+#ifdef CONFIG_INTC_BALANCING
+ k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0);
+#endif
+ }
+ }
+
+ if (hw->prio_regs) {
+ d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
+ GFP_NOWAIT);
+ if (!d->prio)
+ goto err4;
+
+ for (i = 0; i < hw->nr_prio_regs; i++) {
+ smp = IS_SMP(hw->prio_regs[i]);
+ k += save_reg(d, k, hw->prio_regs[i].set_reg, smp);
+ k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp);
+ }
+ }
+
+ if (hw->sense_regs) {
+ d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
+ GFP_NOWAIT);
+ if (!d->sense)
+ goto err5;
+
+ for (i = 0; i < hw->nr_sense_regs; i++)
+ k += save_reg(d, k, hw->sense_regs[i].reg, 0);
+ }
+
+ if (hw->subgroups)
+ for (i = 0; i < hw->nr_subgroups; i++)
+ if (hw->subgroups[i].reg)
+ k+= save_reg(d, k, hw->subgroups[i].reg, 0);
+
+ memcpy(&d->chip, &intc_irq_chip, sizeof(struct irq_chip));
+ d->chip.name = desc->name;
+
+ if (hw->ack_regs)
+ for (i = 0; i < hw->nr_ack_regs; i++)
+ k += save_reg(d, k, hw->ack_regs[i].set_reg, 0);
+ else
+ d->chip.mask_ack = d->chip.disable;
+
+ /* disable bits matching force_disable before registering irqs */
+ if (desc->force_disable)
+ intc_enable_disable_enum(desc, d, desc->force_disable, 0);
+
+ /* disable bits matching force_enable before registering irqs */
+ if (desc->force_enable)
+ intc_enable_disable_enum(desc, d, desc->force_enable, 0);
+
+ BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
+
+ /* register the vectors one by one */
+ for (i = 0; i < hw->nr_vectors; i++) {
+ struct intc_vect *vect = hw->vectors + i;
+ unsigned int irq = evt2irq(vect->vect);
+ struct irq_desc *irq_desc;
+
+ if (!vect->enum_id)
+ continue;
+
+ irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
+ if (unlikely(!irq_desc)) {
+ pr_err("can't get irq_desc for %d\n", irq);
+ continue;
+ }
+
+ intc_irq_xlate_set(irq, vect->enum_id, d);
+ intc_register_irq(desc, d, vect->enum_id, irq);
+
+ for (k = i + 1; k < hw->nr_vectors; k++) {
+ struct intc_vect *vect2 = hw->vectors + k;
+ unsigned int irq2 = evt2irq(vect2->vect);
+
+ if (vect->enum_id != vect2->enum_id)
+ continue;
+
+ /*
+ * In the case of multi-evt handling and sparse
+ * IRQ support, each vector still needs to have
+ * its own backing irq_desc.
+ */
+ irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id());
+ if (unlikely(!irq_desc)) {
+ pr_err("can't get irq_desc for %d\n", irq2);
+ continue;
+ }
+
+ vect2->enum_id = 0;
+
+ /* redirect this interrupts to the first one */
+ set_irq_chip(irq2, &dummy_irq_chip);
+ set_irq_chained_handler(irq2, intc_redirect_irq);
+ set_irq_data(irq2, (void *)irq);
+ }
+ }
+
+ intc_subgroup_init(desc, d);
+
+ /* enable bits matching force_enable after registering irqs */
+ if (desc->force_enable)
+ intc_enable_disable_enum(desc, d, desc->force_enable, 1);
+
+ nr_intc_controllers++;
+
+ return 0;
+err5:
+ kfree(d->prio);
+err4:
+#ifdef CONFIG_SMP
+ kfree(d->smp);
+err3:
+#endif
+ kfree(d->reg);
+err2:
+ for (k = 0; k < d->nr_windows; k++)
+ if (d->window[k].virt)
+ iounmap(d->window[k].virt);
+
+ kfree(d->window);
+err1:
+ kfree(d);
+err0:
+ pr_err("unable to allocate INTC memory\n");
+
+ return -ENOMEM;
+}
+
+static ssize_t
+show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
+{
+ struct intc_desc_int *d;
+
+ d = container_of(dev, struct intc_desc_int, sysdev);
+
+ return sprintf(buf, "%s\n", d->chip.name);
+}
+
+static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
+
+static int intc_suspend(struct sys_device *dev, pm_message_t state)
+{
+ struct intc_desc_int *d;
+ struct irq_desc *desc;
+ int irq;
+
+ /* get intc controller associated with this sysdev */
+ d = container_of(dev, struct intc_desc_int, sysdev);
+
+ switch (state.event) {
+ case PM_EVENT_ON:
+ if (d->state.event != PM_EVENT_FREEZE)
+ break;
+
+ for_each_irq_desc(irq, desc) {
+ /*
+ * This will catch the redirect and VIRQ cases
+ * due to the dummy_irq_chip being inserted.
+ */
+ if (desc->chip != &d->chip)
+ continue;
+ if (desc->status & IRQ_DISABLED)
+ desc->chip->disable(irq);
+ else
+ desc->chip->enable(irq);
+ }
+ break;
+ case PM_EVENT_FREEZE:
+ /* nothing has to be done */
+ break;
+ case PM_EVENT_SUSPEND:
+ /* enable wakeup irqs belonging to this intc controller */
+ for_each_irq_desc(irq, desc) {
+ if (desc->chip != &d->chip)
+ continue;
+ if ((desc->status & IRQ_WAKEUP))
+ desc->chip->enable(irq);
+ }
+ break;
+ }
+
+ d->state = state;
+
+ return 0;
+}
+
+static int intc_resume(struct sys_device *dev)
+{
+ return intc_suspend(dev, PMSG_ON);
+}
+
+struct sysdev_class intc_sysdev_class = {
+ .name = "intc",
+ .suspend = intc_suspend,
+ .resume = intc_resume,
+};
+
+/* register this intc as sysdev to allow suspend/resume */
+static int __init register_intc_sysdevs(void)
+{
+ struct intc_desc_int *d;
+ int error;
+
+ error = sysdev_class_register(&intc_sysdev_class);
+ if (!error) {
+ list_for_each_entry(d, &intc_list, list) {
+ d->sysdev.id = d->index;
+ d->sysdev.cls = &intc_sysdev_class;
+ error = sysdev_register(&d->sysdev);
+ if (error == 0)
+ error = sysdev_create_file(&d->sysdev,
+ &attr_name);
+ if (error)
+ break;
+ }
+ }
+
+ if (error)
+ pr_err("sysdev registration error\n");
+
+ return error;
+}
+device_initcall(register_intc_sysdevs);
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c
new file mode 100644
index 000000000000..6caecdffe201
--- /dev/null
+++ b/drivers/sh/intc/dynamic.c
@@ -0,0 +1,135 @@
+/*
+ * Dynamic IRQ management
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * Modelled after arch/x86/kernel/apic/io_apic.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/irq.h>
+#include <linux/bitmap.h>
+#include <linux/spinlock.h>
+#include "internals.h" /* only for activate_irq() damage.. */
+
+/*
+ * The intc_irq_map provides a global map of bound IRQ vectors for a
+ * given platform. Allocation of IRQs are either static through the CPU
+ * vector map, or dynamic in the case of board mux vectors or MSI.
+ *
+ * As this is a central point for all IRQ controllers on the system,
+ * each of the available sources are mapped out here. This combined with
+ * sparseirq makes it quite trivial to keep the vector map tightly packed
+ * when dynamically creating IRQs, as well as tying in to otherwise
+ * unused irq_desc positions in the sparse array.
+ */
+static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
+static DEFINE_RAW_SPINLOCK(vector_lock);
+
+/*
+ * Dynamic IRQ allocation and deallocation
+ */
+unsigned int create_irq_nr(unsigned int irq_want, int node)
+{
+ unsigned int irq = 0, new;
+ unsigned long flags;
+ struct irq_desc *desc;
+
+ raw_spin_lock_irqsave(&vector_lock, flags);
+
+ /*
+ * First try the wanted IRQ
+ */
+ if (test_and_set_bit(irq_want, intc_irq_map) == 0) {
+ new = irq_want;
+ } else {
+ /* .. then fall back to scanning. */
+ new = find_first_zero_bit(intc_irq_map, nr_irqs);
+ if (unlikely(new == nr_irqs))
+ goto out_unlock;
+
+ __set_bit(new, intc_irq_map);
+ }
+
+ desc = irq_to_desc_alloc_node(new, node);
+ if (unlikely(!desc)) {
+ pr_err("can't get irq_desc for %d\n", new);
+ goto out_unlock;
+ }
+
+ desc = move_irq_desc(desc, node);
+ irq = new;
+
+out_unlock:
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+
+ if (irq > 0) {
+ dynamic_irq_init(irq);
+ activate_irq(irq);
+ }
+
+ return irq;
+}
+
+int create_irq(void)
+{
+ int nid = cpu_to_node(smp_processor_id());
+ int irq;
+
+ irq = create_irq_nr(NR_IRQS_LEGACY, nid);
+ if (irq == 0)
+ irq = -1;
+
+ return irq;
+}
+
+void destroy_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ dynamic_irq_cleanup(irq);
+
+ raw_spin_lock_irqsave(&vector_lock, flags);
+ __clear_bit(irq, intc_irq_map);
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+int reserve_irq_vector(unsigned int irq)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ raw_spin_lock_irqsave(&vector_lock, flags);
+ if (test_and_set_bit(irq, intc_irq_map))
+ ret = -EBUSY;
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+
+ return ret;
+}
+
+void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
+{
+ unsigned long flags;
+ int i;
+
+ raw_spin_lock_irqsave(&vector_lock, flags);
+ for (i = 0; i < nr_vecs; i++)
+ __set_bit(evt2irq(vectors[i].vect), intc_irq_map);
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+void reserve_irq_legacy(void)
+{
+ unsigned long flags;
+ int i, j;
+
+ raw_spin_lock_irqsave(&vector_lock, flags);
+ j = find_first_bit(intc_irq_map, nr_irqs);
+ for (i = 0; i < j; i++)
+ __set_bit(i, intc_irq_map);
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+}
diff --git a/drivers/sh/intc/handle.c b/drivers/sh/intc/handle.c
new file mode 100644
index 000000000000..057ce56829bf
--- /dev/null
+++ b/drivers/sh/intc/handle.c
@@ -0,0 +1,307 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include "internals.h"
+
+static unsigned long ack_handle[NR_IRQS];
+
+static intc_enum __init intc_grp_id(struct intc_desc *desc,
+ intc_enum enum_id)
+{
+ struct intc_group *g = desc->hw.groups;
+ unsigned int i, j;
+
+ for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) {
+ g = desc->hw.groups + i;
+
+ for (j = 0; g->enum_ids[j]; j++) {
+ if (g->enum_ids[j] != enum_id)
+ continue;
+
+ return g->enum_id;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int __init _intc_mask_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id,
+ unsigned int *reg_idx,
+ unsigned int *fld_idx)
+{
+ struct intc_mask_reg *mr = desc->hw.mask_regs;
+ unsigned int fn, mode;
+ unsigned long reg_e, reg_d;
+
+ while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) {
+ mr = desc->hw.mask_regs + *reg_idx;
+
+ for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) {
+ if (mr->enum_ids[*fld_idx] != enum_id)
+ continue;
+
+ if (mr->set_reg && mr->clr_reg) {
+ fn = REG_FN_WRITE_BASE;
+ mode = MODE_DUAL_REG;
+ reg_e = mr->clr_reg;
+ reg_d = mr->set_reg;
+ } else {
+ fn = REG_FN_MODIFY_BASE;
+ if (mr->set_reg) {
+ mode = MODE_ENABLE_REG;
+ reg_e = mr->set_reg;
+ reg_d = mr->set_reg;
+ } else {
+ mode = MODE_MASK_REG;
+ reg_e = mr->clr_reg;
+ reg_d = mr->clr_reg;
+ }
+ }
+
+ fn += (mr->reg_width >> 3) - 1;
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ 1,
+ (mr->reg_width - 1) - *fld_idx);
+ }
+
+ *fld_idx = 0;
+ (*reg_idx)++;
+ }
+
+ return 0;
+}
+
+unsigned int __init
+intc_get_mask_handle(struct intc_desc *desc, struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps)
+{
+ unsigned int i = 0;
+ unsigned int j = 0;
+ unsigned int ret;
+
+ ret = _intc_mask_data(desc, d, enum_id, &i, &j);
+ if (ret)
+ return ret;
+
+ if (do_grps)
+ return intc_get_mask_handle(desc, d, intc_grp_id(desc, enum_id), 0);
+
+ return 0;
+}
+
+static unsigned int __init _intc_prio_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id,
+ unsigned int *reg_idx,
+ unsigned int *fld_idx)
+{
+ struct intc_prio_reg *pr = desc->hw.prio_regs;
+ unsigned int fn, n, mode, bit;
+ unsigned long reg_e, reg_d;
+
+ while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) {
+ pr = desc->hw.prio_regs + *reg_idx;
+
+ for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) {
+ if (pr->enum_ids[*fld_idx] != enum_id)
+ continue;
+
+ if (pr->set_reg && pr->clr_reg) {
+ fn = REG_FN_WRITE_BASE;
+ mode = MODE_PCLR_REG;
+ reg_e = pr->set_reg;
+ reg_d = pr->clr_reg;
+ } else {
+ fn = REG_FN_MODIFY_BASE;
+ mode = MODE_PRIO_REG;
+ if (!pr->set_reg)
+ BUG();
+ reg_e = pr->set_reg;
+ reg_d = pr->set_reg;
+ }
+
+ fn += (pr->reg_width >> 3) - 1;
+ n = *fld_idx + 1;
+
+ BUG_ON(n * pr->field_width > pr->reg_width);
+
+ bit = pr->reg_width - (n * pr->field_width);
+
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ pr->field_width, bit);
+ }
+
+ *fld_idx = 0;
+ (*reg_idx)++;
+ }
+
+ return 0;
+}
+
+unsigned int __init
+intc_get_prio_handle(struct intc_desc *desc, struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps)
+{
+ unsigned int i = 0;
+ unsigned int j = 0;
+ unsigned int ret;
+
+ ret = _intc_prio_data(desc, d, enum_id, &i, &j);
+ if (ret)
+ return ret;
+
+ if (do_grps)
+ return intc_get_prio_handle(desc, d, intc_grp_id(desc, enum_id), 0);
+
+ return 0;
+}
+
+static unsigned int __init intc_ack_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id)
+{
+ struct intc_mask_reg *mr = desc->hw.ack_regs;
+ unsigned int i, j, fn, mode;
+ unsigned long reg_e, reg_d;
+
+ for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) {
+ mr = desc->hw.ack_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+ if (mr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = REG_FN_MODIFY_BASE;
+ mode = MODE_ENABLE_REG;
+ reg_e = mr->set_reg;
+ reg_d = mr->set_reg;
+
+ fn += (mr->reg_width >> 3) - 1;
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ 1,
+ (mr->reg_width - 1) - j);
+ }
+ }
+
+ return 0;
+}
+
+static void intc_enable_disable(struct intc_desc_int *d,
+ unsigned long handle, int do_enable)
+{
+ unsigned long addr;
+ unsigned int cpu;
+ unsigned long (*fn)(unsigned long, unsigned long,
+ unsigned long (*)(unsigned long, unsigned long,
+ unsigned long),
+ unsigned int);
+
+ if (do_enable) {
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+ fn = intc_enable_noprio_fns[_INTC_MODE(handle)];
+ fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
+ }
+ } else {
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+ fn = intc_disable_fns[_INTC_MODE(handle)];
+ fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
+ }
+ }
+}
+
+void __init intc_enable_disable_enum(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int enable)
+{
+ unsigned int i, j, data;
+
+ /* go through and enable/disable all mask bits */
+ i = j = 0;
+ do {
+ data = _intc_mask_data(desc, d, enum_id, &i, &j);
+ if (data)
+ intc_enable_disable(d, data, enable);
+ j++;
+ } while (data);
+
+ /* go through and enable/disable all priority fields */
+ i = j = 0;
+ do {
+ data = _intc_prio_data(desc, d, enum_id, &i, &j);
+ if (data)
+ intc_enable_disable(d, data, enable);
+
+ j++;
+ } while (data);
+}
+
+unsigned int __init
+intc_get_sense_handle(struct intc_desc *desc, struct intc_desc_int *d,
+ intc_enum enum_id)
+{
+ struct intc_sense_reg *sr = desc->hw.sense_regs;
+ unsigned int i, j, fn, bit;
+
+ for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) {
+ sr = desc->hw.sense_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
+ if (sr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = REG_FN_MODIFY_BASE;
+ fn += (sr->reg_width >> 3) - 1;
+
+ BUG_ON((j + 1) * sr->field_width > sr->reg_width);
+
+ bit = sr->reg_width - ((j + 1) * sr->field_width);
+
+ return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
+ 0, sr->field_width, bit);
+ }
+ }
+
+ return 0;
+}
+
+
+void intc_set_ack_handle(unsigned int irq, struct intc_desc *desc,
+ struct intc_desc_int *d, intc_enum id)
+{
+ unsigned long flags;
+
+ /*
+ * Nothing to do for this IRQ.
+ */
+ if (!desc->hw.ack_regs)
+ return;
+
+ raw_spin_lock_irqsave(&intc_big_lock, flags);
+ ack_handle[irq] = intc_ack_data(desc, d, id);
+ raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
+
+unsigned long intc_get_ack_handle(unsigned int irq)
+{
+ return ack_handle[irq];
+}
diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h
new file mode 100644
index 000000000000..d49482c623fa
--- /dev/null
+++ b/drivers/sh/intc/internals.h
@@ -0,0 +1,186 @@
+#include <linux/sh_intc.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/radix-tree.h>
+#include <linux/sysdev.h>
+
+#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
+ ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
+ ((addr_e) << 16) | ((addr_d << 24)))
+
+#define _INTC_SHIFT(h) (h & 0x1f)
+#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
+#define _INTC_FN(h) ((h >> 9) & 0xf)
+#define _INTC_MODE(h) ((h >> 13) & 0x7)
+#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
+#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)
+
+#ifdef CONFIG_SMP
+#define IS_SMP(x) (x.smp)
+#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
+#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
+#else
+#define IS_SMP(x) 0
+#define INTC_REG(d, x, c) (d->reg[(x)])
+#define SMP_NR(d, x) 1
+#endif
+
+struct intc_handle_int {
+ unsigned int irq;
+ unsigned long handle;
+};
+
+struct intc_window {
+ phys_addr_t phys;
+ void __iomem *virt;
+ unsigned long size;
+};
+
+struct intc_map_entry {
+ intc_enum enum_id;
+ struct intc_desc_int *desc;
+};
+
+struct intc_subgroup_entry {
+ unsigned int pirq;
+ intc_enum enum_id;
+ unsigned long handle;
+};
+
+struct intc_desc_int {
+ struct list_head list;
+ struct sys_device sysdev;
+ struct radix_tree_root tree;
+ pm_message_t state;
+ raw_spinlock_t lock;
+ unsigned int index;
+ unsigned long *reg;
+#ifdef CONFIG_SMP
+ unsigned long *smp;
+#endif
+ unsigned int nr_reg;
+ struct intc_handle_int *prio;
+ unsigned int nr_prio;
+ struct intc_handle_int *sense;
+ unsigned int nr_sense;
+ struct intc_window *window;
+ unsigned int nr_windows;
+ struct irq_chip chip;
+};
+
+
+enum {
+ REG_FN_ERR = 0,
+ REG_FN_TEST_BASE = 1,
+ REG_FN_WRITE_BASE = 5,
+ REG_FN_MODIFY_BASE = 9
+};
+
+enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
+ MODE_MASK_REG, /* Bit(s) set -> interrupt disabled */
+ MODE_DUAL_REG, /* Two registers, set bit to enable / disable */
+ MODE_PRIO_REG, /* Priority value written to enable interrupt */
+ MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */
+};
+
+static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
+{
+ struct irq_chip *chip = get_irq_chip(irq);
+
+ return container_of(chip, struct intc_desc_int, chip);
+}
+
+/*
+ * Grumble.
+ */
+static inline void activate_irq(int irq)
+{
+#ifdef CONFIG_ARM
+ /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+ * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
+ */
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ /* same effect on other architectures */
+ set_irq_noprobe(irq);
+#endif
+}
+
+/* access.c */
+extern unsigned long
+(*intc_reg_fns[])(unsigned long addr, unsigned long h, unsigned long data);
+
+extern unsigned long
+(*intc_enable_fns[])(unsigned long addr, unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long, unsigned long),
+ unsigned int irq);
+extern unsigned long
+(*intc_disable_fns[])(unsigned long addr, unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long, unsigned long),
+ unsigned int irq);
+extern unsigned long
+(*intc_enable_noprio_fns[])(unsigned long addr, unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long, unsigned long),
+ unsigned int irq);
+
+unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address);
+unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address);
+unsigned int intc_set_field_from_handle(unsigned int value,
+ unsigned int field_value,
+ unsigned int handle);
+unsigned long intc_get_field_from_handle(unsigned int value,
+ unsigned int handle);
+
+/* balancing.c */
+#ifdef CONFIG_INTC_BALANCING
+void intc_balancing_enable(unsigned int irq);
+void intc_balancing_disable(unsigned int irq);
+void intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
+ struct intc_desc_int *d, intc_enum id);
+#else
+static inline void intc_balancing_enable(unsigned int irq) { }
+static inline void intc_balancing_disable(unsigned int irq) { }
+static inline void
+intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
+ struct intc_desc_int *d, intc_enum id) { }
+#endif
+
+/* chip.c */
+extern struct irq_chip intc_irq_chip;
+void _intc_enable(unsigned int irq, unsigned long handle);
+
+/* core.c */
+extern struct list_head intc_list;
+extern raw_spinlock_t intc_big_lock;
+extern unsigned int nr_intc_controllers;
+extern struct sysdev_class intc_sysdev_class;
+
+unsigned int intc_get_dfl_prio_level(void);
+unsigned int intc_get_prio_level(unsigned int irq);
+void intc_set_prio_level(unsigned int irq, unsigned int level);
+
+/* handle.c */
+unsigned int intc_get_mask_handle(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps);
+unsigned int intc_get_prio_handle(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps);
+unsigned int intc_get_sense_handle(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id);
+void intc_set_ack_handle(unsigned int irq, struct intc_desc *desc,
+ struct intc_desc_int *d, intc_enum id);
+unsigned long intc_get_ack_handle(unsigned int irq);
+void intc_enable_disable_enum(struct intc_desc *desc, struct intc_desc_int *d,
+ intc_enum enum_id, int enable);
+
+/* virq.c */
+void intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d);
+void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d);
+struct intc_map_entry *intc_irq_xlate_get(unsigned int irq);
diff --git a/drivers/sh/intc/userimask.c b/drivers/sh/intc/userimask.c
new file mode 100644
index 000000000000..e32304b66cf1
--- /dev/null
+++ b/drivers/sh/intc/userimask.c
@@ -0,0 +1,83 @@
+/*
+ * Support for hardware-assisted userspace interrupt masking.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/errno.h>
+#include <linux/sysdev.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/sizes.h>
+#include "internals.h"
+
+static void __iomem *uimask;
+
+static ssize_t
+show_intc_userimask(struct sysdev_class *cls,
+ struct sysdev_class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf);
+}
+
+static ssize_t
+store_intc_userimask(struct sysdev_class *cls,
+ struct sysdev_class_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long level;
+
+ level = simple_strtoul(buf, NULL, 10);
+
+ /*
+ * Minimal acceptable IRQ levels are in the 2 - 16 range, but
+ * these are chomped so as to not interfere with normal IRQs.
+ *
+ * Level 1 is a special case on some CPUs in that it's not
+ * directly settable, but given that USERIMASK cuts off below a
+ * certain level, we don't care about this limitation here.
+ * Level 0 on the other hand equates to user masking disabled.
+ *
+ * We use the default priority level as a cut off so that only
+ * special case opt-in IRQs can be mangled.
+ */
+ if (level >= intc_get_dfl_prio_level())
+ return -EINVAL;
+
+ __raw_writel(0xa5 << 24 | level << 4, uimask);
+
+ return count;
+}
+
+static SYSDEV_CLASS_ATTR(userimask, S_IRUSR | S_IWUSR,
+ show_intc_userimask, store_intc_userimask);
+
+
+static int __init userimask_sysdev_init(void)
+{
+ if (unlikely(!uimask))
+ return -ENXIO;
+
+ return sysdev_class_create_file(&intc_sysdev_class, &attr_userimask);
+}
+late_initcall(userimask_sysdev_init);
+
+int register_intc_userimask(unsigned long addr)
+{
+ if (unlikely(uimask))
+ return -EBUSY;
+
+ uimask = ioremap_nocache(addr, SZ_4K);
+ if (unlikely(!uimask))
+ return -ENOMEM;
+
+ pr_info("userimask support registered for levels 0 -> %d\n",
+ intc_get_dfl_prio_level() - 1);
+
+ return 0;
+}
diff --git a/drivers/sh/intc/virq-debugfs.c b/drivers/sh/intc/virq-debugfs.c
new file mode 100644
index 000000000000..9e62ba9311f0
--- /dev/null
+++ b/drivers/sh/intc/virq-debugfs.c
@@ -0,0 +1,64 @@
+/*
+ * Support for virtual IRQ subgroups debugfs mapping.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * Modelled after arch/powerpc/kernel/irq.c.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/seq_file.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/debugfs.h>
+#include "internals.h"
+
+static int intc_irq_xlate_debug(struct seq_file *m, void *priv)
+{
+ int i;
+
+ seq_printf(m, "%-5s %-7s %-15s\n", "irq", "enum", "chip name");
+
+ for (i = 1; i < nr_irqs; i++) {
+ struct intc_map_entry *entry = intc_irq_xlate_get(i);
+ struct intc_desc_int *desc = entry->desc;
+
+ if (!desc)
+ continue;
+
+ seq_printf(m, "%5d ", i);
+ seq_printf(m, "0x%05x ", entry->enum_id);
+ seq_printf(m, "%-15s\n", desc->chip.name);
+ }
+
+ return 0;
+}
+
+static int intc_irq_xlate_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, intc_irq_xlate_debug, inode->i_private);
+}
+
+static const struct file_operations intc_irq_xlate_fops = {
+ .open = intc_irq_xlate_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init intc_irq_xlate_init(void)
+{
+ /*
+ * XXX.. use arch_debugfs_dir here when all of the intc users are
+ * converted.
+ */
+ if (debugfs_create_file("intc_irq_xlate", S_IRUGO, NULL, NULL,
+ &intc_irq_xlate_fops) == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+fs_initcall(intc_irq_xlate_init);
diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c
new file mode 100644
index 000000000000..643dfd4d2057
--- /dev/null
+++ b/drivers/sh/intc/virq.c
@@ -0,0 +1,255 @@
+/*
+ * Support for virtual IRQ subgroups.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/radix-tree.h>
+#include <linux/spinlock.h>
+#include "internals.h"
+
+static struct intc_map_entry intc_irq_xlate[NR_IRQS];
+
+struct intc_virq_list {
+ unsigned int irq;
+ struct intc_virq_list *next;
+};
+
+#define for_each_virq(entry, head) \
+ for (entry = head; entry; entry = entry->next)
+
+/*
+ * Tags for the radix tree
+ */
+#define INTC_TAG_VIRQ_NEEDS_ALLOC 0
+
+void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&intc_big_lock, flags);
+ intc_irq_xlate[irq].enum_id = id;
+ intc_irq_xlate[irq].desc = d;
+ raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
+
+struct intc_map_entry *intc_irq_xlate_get(unsigned int irq)
+{
+ return intc_irq_xlate + irq;
+}
+
+int intc_irq_lookup(const char *chipname, intc_enum enum_id)
+{
+ struct intc_map_entry *ptr;
+ struct intc_desc_int *d;
+ int irq = -1;
+
+ list_for_each_entry(d, &intc_list, list) {
+ int tagged;
+
+ if (strcmp(d->chip.name, chipname) != 0)
+ continue;
+
+ /*
+ * Catch early lookups for subgroup VIRQs that have not
+ * yet been allocated an IRQ. This already includes a
+ * fast-path out if the tree is untagged, so there is no
+ * need to explicitly test the root tree.
+ */
+ tagged = radix_tree_tag_get(&d->tree, enum_id,
+ INTC_TAG_VIRQ_NEEDS_ALLOC);
+ if (unlikely(tagged))
+ break;
+
+ ptr = radix_tree_lookup(&d->tree, enum_id);
+ if (ptr) {
+ irq = ptr - intc_irq_xlate;
+ break;
+ }
+ }
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(intc_irq_lookup);
+
+static int add_virq_to_pirq(unsigned int irq, unsigned int virq)
+{
+ struct intc_virq_list **last, *entry;
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ /* scan for duplicates */
+ last = (struct intc_virq_list **)&desc->handler_data;
+ for_each_virq(entry, desc->handler_data) {
+ if (entry->irq == virq)
+ return 0;
+ last = &entry->next;
+ }
+
+ entry = kzalloc(sizeof(struct intc_virq_list), GFP_ATOMIC);
+ if (!entry) {
+ pr_err("can't allocate VIRQ mapping for %d\n", virq);
+ return -ENOMEM;
+ }
+
+ entry->irq = virq;
+
+ *last = entry;
+
+ return 0;
+}
+
+static void intc_virq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct intc_virq_list *entry, *vlist = get_irq_data(irq);
+ struct intc_desc_int *d = get_intc_desc(irq);
+
+ desc->chip->mask_ack(irq);
+
+ for_each_virq(entry, vlist) {
+ unsigned long addr, handle;
+
+ handle = (unsigned long)get_irq_data(entry->irq);
+ addr = INTC_REG(d, _INTC_ADDR_E(handle), 0);
+
+ if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0))
+ generic_handle_irq(entry->irq);
+ }
+
+ desc->chip->unmask(irq);
+}
+
+static unsigned long __init intc_subgroup_data(struct intc_subgroup *subgroup,
+ struct intc_desc_int *d,
+ unsigned int index)
+{
+ unsigned int fn = REG_FN_TEST_BASE + (subgroup->reg_width >> 3) - 1;
+
+ return _INTC_MK(fn, MODE_ENABLE_REG, intc_get_reg(d, subgroup->reg),
+ 0, 1, (subgroup->reg_width - 1) - index);
+}
+
+static void __init intc_subgroup_init_one(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ struct intc_subgroup *subgroup)
+{
+ struct intc_map_entry *mapped;
+ unsigned int pirq;
+ unsigned long flags;
+ int i;
+
+ mapped = radix_tree_lookup(&d->tree, subgroup->parent_id);
+ if (!mapped) {
+ WARN_ON(1);
+ return;
+ }
+
+ pirq = mapped - intc_irq_xlate;
+
+ raw_spin_lock_irqsave(&d->lock, flags);
+
+ for (i = 0; i < ARRAY_SIZE(subgroup->enum_ids); i++) {
+ struct intc_subgroup_entry *entry;
+ int err;
+
+ if (!subgroup->enum_ids[i])
+ continue;
+
+ entry = kmalloc(sizeof(*entry), GFP_NOWAIT);
+ if (!entry)
+ break;
+
+ entry->pirq = pirq;
+ entry->enum_id = subgroup->enum_ids[i];
+ entry->handle = intc_subgroup_data(subgroup, d, i);
+
+ err = radix_tree_insert(&d->tree, entry->enum_id, entry);
+ if (unlikely(err < 0))
+ break;
+
+ radix_tree_tag_set(&d->tree, entry->enum_id,
+ INTC_TAG_VIRQ_NEEDS_ALLOC);
+ }
+
+ raw_spin_unlock_irqrestore(&d->lock, flags);
+}
+
+void __init intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d)
+{
+ int i;
+
+ if (!desc->hw.subgroups)
+ return;
+
+ for (i = 0; i < desc->hw.nr_subgroups; i++)
+ intc_subgroup_init_one(desc, d, desc->hw.subgroups + i);
+}
+
+static void __init intc_subgroup_map(struct intc_desc_int *d)
+{
+ struct intc_subgroup_entry *entries[32];
+ unsigned long flags;
+ unsigned int nr_found;
+ int i;
+
+ raw_spin_lock_irqsave(&d->lock, flags);
+
+restart:
+ nr_found = radix_tree_gang_lookup_tag_slot(&d->tree,
+ (void ***)entries, 0, ARRAY_SIZE(entries),
+ INTC_TAG_VIRQ_NEEDS_ALLOC);
+
+ for (i = 0; i < nr_found; i++) {
+ struct intc_subgroup_entry *entry;
+ int irq;
+
+ entry = radix_tree_deref_slot((void **)entries[i]);
+ if (unlikely(!entry))
+ continue;
+ if (unlikely(entry == RADIX_TREE_RETRY))
+ goto restart;
+
+ irq = create_irq();
+ if (unlikely(irq < 0)) {
+ pr_err("no more free IRQs, bailing..\n");
+ break;
+ }
+
+ pr_info("Setting up a chained VIRQ from %d -> %d\n",
+ irq, entry->pirq);
+
+ intc_irq_xlate_set(irq, entry->enum_id, d);
+
+ set_irq_chip_and_handler_name(irq, get_irq_chip(entry->pirq),
+ handle_simple_irq, "virq");
+ set_irq_chip_data(irq, get_irq_chip_data(entry->pirq));
+
+ set_irq_data(irq, (void *)entry->handle);
+
+ set_irq_chained_handler(entry->pirq, intc_virq_handler);
+ add_virq_to_pirq(entry->pirq, irq);
+
+ radix_tree_tag_clear(&d->tree, entry->enum_id,
+ INTC_TAG_VIRQ_NEEDS_ALLOC);
+ radix_tree_replace_slot((void **)entries[i],
+ &intc_irq_xlate[irq]);
+ }
+
+ raw_spin_unlock_irqrestore(&d->lock, flags);
+}
+
+void __init intc_finalize(void)
+{
+ struct intc_desc_int *d;
+
+ list_for_each_entry(d, &intc_list, list)
+ if (radix_tree_tagged(&d->tree, INTC_TAG_VIRQ_NEEDS_ALLOC))
+ intc_subgroup_map(d);
+}
diff --git a/drivers/sh/pfc.c b/drivers/sh/pfc.c
index cf0303acab8e..75934e3ea34e 100644
--- a/drivers/sh/pfc.c
+++ b/drivers/sh/pfc.c
@@ -7,6 +7,8 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -559,10 +561,8 @@ static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
struct pinmux_data_reg *dr = NULL;
int bit = 0;
- if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) {
- BUG();
- return 0;
- }
+ if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
+ return -EINVAL;
return gpio_read_reg(dr->reg, dr->reg_width, 1, bit);
}
@@ -581,7 +581,7 @@ int register_pinmux(struct pinmux_info *pip)
{
struct gpio_chip *chip = &pip->chip;
- pr_info("sh pinmux: %s handling gpio %d -> %d\n",
+ pr_info("%s handling gpio %d -> %d\n",
pip->name, pip->first_gpio, pip->last_gpio);
setup_data_regs(pip);
@@ -602,3 +602,10 @@ int register_pinmux(struct pinmux_info *pip)
return gpiochip_add(chip);
}
+
+int unregister_pinmux(struct pinmux_info *pip)
+{
+ pr_info("%s deregistering\n", pip->name);
+
+ return gpiochip_remove(&pip->chip);
+}
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 335311a98fdc..8e03e7600239 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -139,8 +139,6 @@ source "drivers/staging/adis16255/Kconfig"
source "drivers/staging/xgifb/Kconfig"
-source "drivers/staging/mrst-touchscreen/Kconfig"
-
source "drivers/staging/msm/Kconfig"
source "drivers/staging/lirc/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index e3f1e1b6095e..0e7d7559d379 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -51,7 +51,6 @@ obj-$(CONFIG_CXT1E1) += cxt1e1/
obj-$(CONFIG_TI_ST) += ti-st/
obj-$(CONFIG_ADIS16255) += adis16255/
obj-$(CONFIG_FB_XGI) += xgifb/
-obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/
obj-$(CONFIG_MSM_STAGING) += msm/
obj-$(CONFIG_EASYCAP) += easycap/
obj-$(CONFIG_SOLO6X10) += solo6x10/
diff --git a/drivers/staging/mrst-touchscreen/Kconfig b/drivers/staging/mrst-touchscreen/Kconfig
deleted file mode 100644
index c2af49217084..000000000000
--- a/drivers/staging/mrst-touchscreen/Kconfig
+++ /dev/null
@@ -1,7 +0,0 @@
-config TOUCHSCREEN_INTEL_MID
- tristate "Intel MID platform resistive touchscreen"
- depends on INTEL_SCU_IPC
- default y
- help
- Say Y here if you have a Intel MID based touchscreen
- If unsure, say N.
diff --git a/drivers/staging/mrst-touchscreen/Makefile b/drivers/staging/mrst-touchscreen/Makefile
deleted file mode 100644
index 2d638b0d70bf..000000000000
--- a/drivers/staging/mrst-touchscreen/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) := intel_mid_touch.o
-
-
diff --git a/drivers/staging/mrst-touchscreen/TODO b/drivers/staging/mrst-touchscreen/TODO
deleted file mode 100644
index 7157028d634a..000000000000
--- a/drivers/staging/mrst-touchscreen/TODO
+++ /dev/null
@@ -1,2 +0,0 @@
-- Move the driver to not think it is SPI (requires fixing some of the SFI
- and firmware side)
diff --git a/drivers/staging/mrst-touchscreen/intel-mid-touch.c b/drivers/staging/mrst-touchscreen/intel-mid-touch.c
deleted file mode 100644
index abba22f921be..000000000000
--- a/drivers/staging/mrst-touchscreen/intel-mid-touch.c
+++ /dev/null
@@ -1,864 +0,0 @@
-/*
- * intel_mid_touch.c - Intel MID Resistive Touch Screen Driver
- *
- * Copyright (C) 2008 Intel Corp
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * 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; ifnot, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
- * Ramesh Agarwal (ramesh.agarwal@intel.com)
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * TODO:
- * kill off mrstouch_debug eventually
- * review conversion of r/m/w sequences
- * Replace interrupt mutex abuse
- * Kill of mrstouchdevp pointer
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/param.h>
-#include <linux/spi/spi.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <asm/intel_scu_ipc.h>
-
-
-#if defined(MRSTOUCH_DEBUG)
-#define mrstouch_debug(fmt, args...)\
- do { \
- printk(KERN_DEBUG "\n[MRSTOUCH(%d)] - ", __LINE__); \
- printk(KERN_DEBUG fmt, ##args); \
- } while (0);
-#else
-#define mrstouch_debug(fmt, args...)
-#endif
-
-/* PMIC Interrupt registers */
-#define PMIC_REG_ID1 0x00 /*PMIC ID1 register */
-
-/* PMIC Interrupt registers */
-#define PMIC_REG_INT 0x04 /*PMIC interrupt register */
-#define PMIC_REG_MINT 0x05 /*PMIC interrupt mask register */
-
-/* ADC Interrupt registers */
-#define PMIC_REG_ADCINT 0x5F /*ADC interrupt register */
-#define PMIC_REG_MADCINT 0x60 /*ADC interrupt mask register */
-
-/* ADC Control registers */
-#define PMIC_REG_ADCCNTL1 0x61 /*ADC control register */
-
-/* ADC Channel Selection registers */
-#define PMICADDR0 0xA4
-#define END_OF_CHANNEL 0x1F
-
-/* ADC Result register */
-#define PMIC_REG_ADCSNS0H 0x64
-
-/* ADC channels for touch screen */
-#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */
-#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */
-#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */
-#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */
-
-/* Touch screen coordinate constants */
-#define TOUCH_PRESSURE 50
-#define TOUCH_PRESSURE_FS 100
-
-#define XMOVE_LIMIT 5
-#define YMOVE_LIMIT 5
-#define XYMOVE_CNT 3
-
-#define MAX_10BIT ((1<<10)-1)
-
-/* Touch screen channel BIAS constants */
-#define XBIAS 0x20
-#define YBIAS 0x40
-#define ZBIAS 0x80
-
-/* Touch screen coordinates */
-#define MIN_X 10
-#define MAX_X 1024
-#define MIN_Y 10
-#define MAX_Y 1024
-#define WAIT_ADC_COMPLETION 10
-
-/* PMIC ADC round robin delays */
-#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
-#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */
-
-/* PMIC Vendor Identifiers */
-#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */
-#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
-#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
-#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
-
-/* Touch screen device structure */
-struct mrstouch_dev {
- struct spi_device *spi; /* SPI device associated with touch screen */
- struct input_dev *input; /* input device for touchscreen*/
- char phys[32]; /* Device name */
- struct task_struct *pendet_thrd; /* PENDET interrupt handler */
- struct mutex lock; /* Sync between interrupt and PENDET handler */
- bool busy; /* Busy flag */
- u16 asr; /* Address selection register */
- int irq; /* Touch screen IRQ # */
- uint vendor; /* PMIC vendor */
- uint rev; /* PMIC revision */
- bool suspended; /* Device suspended status */
- bool disabled; /* Device disabled status */
- u16 x; /* X coordinate */
- u16 y; /* Y coordinate */
- bool pendown; /* PEN position */
-} ;
-
-
-/* Global Pointer to Touch screen device */
-static struct mrstouch_dev *mrstouchdevp;
-
-/* Utility to read PMIC ID */
-static int mrstouch_pmic_id(uint *vendor, uint *rev)
-{
- int err;
- u8 r;
-
- err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
- if (err)
- return err;
-
- *vendor = r & 0x7;
- *rev = (r >> 3) & 0x7;
-
- return 0;
-}
-
-/*
- * Parse ADC channels to find end of the channel configured by other ADC user
- * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
- */
-static int mrstouch_chan_parse(struct mrstouch_dev *tsdev)
-{
- int err, i, j, found;
- u32 r32;
-
- found = -1;
-
- for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
- if (found >= 0)
- break;
-
- err = intel_scu_ipc_ioread32(PMICADDR0, &r32);
- if (err)
- return err;
-
- for (j = 0; j < 32; j+= 8) {
- if (((r32 >> j) & 0xFF) == END_OF_CHANNEL) {
- found = i;
- break;
- }
- }
- }
- if (found < 0)
- return 0;
-
- if (tsdev->vendor == PMIC_VENDOR_FS) {
- if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
- return -ENOSPC;
- } else {
- if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
- return -ENOSPC;
- }
- return found;
-}
-
-/* Utility to enable/disable pendet.
- * pendet set to true enables PENDET interrupt
- * pendet set to false disables PENDET interrupt
- * Also clears RND mask bit
-*/
-static int pendet_enable(struct mrstouch_dev *tsdev, bool pendet)
-{
- u16 reg;
- u8 r;
- u8 pendet_enabled = 0;
- int retry = 0;
- int err;
-
- err = intel_scu_ipc_ioread16(PMIC_REG_MADCINT, &reg);
- if (err)
- return err;
-
- if (pendet) {
- reg &= ~0x0005;
- reg |= 0x2000; /* Enable pendet */
- } else
- reg &= 0xDFFF; /* Disable pendet */
-
- /* Set MADCINT and update ADCCNTL1 (next reg byte) */
- err = intel_scu_ipc_iowrite16(PMIC_REG_MADCINT, reg);
- if (!pendet || err)
- return err;
-
- /*
- * Sometimes even after the register write succeeds
- * the PMIC register value is not updated. Retry few iterations
- * to enable pendet.
- */
-
- err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
- pendet_enabled = (r >> 5) & 0x01;
-
- retry = 0;
- while (!err && !pendet_enabled) {
- retry++;
- msleep(10);
- err = intel_scu_ipc_iowrite8(PMIC_REG_ADCCNTL1, reg >> 8);
- if (err)
- break;
- err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
- if (err == 0)
- pendet_enabled = (r >> 5) & 0x01;
- if (retry >= 10) {
- dev_err(&tsdev->spi->dev, "Touch screen disabled.\n");
- return -EIO;
- }
- }
- return 0;
-}
-
-/* To read PMIC ADC touch screen result
- * Reads ADC storage registers for higher 7 and lower 3 bits
- * converts the two readings to single value and turns off gain bit
- */
-static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
-{
- int err;
- u16 result;
- u32 res;
-
- result = PMIC_REG_ADCSNS0H + offset;
-
- if (chan == MRST_TS_CHAN12)
- result += 4;
-
- err = intel_scu_ipc_ioread32(result, &res);
- if (err)
- return err;
-
- /* Mash the bits up */
-
- *vp = (res & 0xFF) << 3; /* Highest 7 bits */
- *vp |= (res >> 8) & 0x07; /* Lower 3 bits */
- *vp &= 0x3FF;
-
- res >>= 16;
-
- *vm = (res & 0xFF) << 3; /* Highest 7 bits */
- *vm |= (res >> 8) & 0x07; /* Lower 3 bits */
- *vm &= 0x3FF;
-
- return 0;
-}
-
-/* To configure touch screen channels
- * Writes touch screen channels to ADC address selection registers
- */
-static int mrstouch_ts_chan_set(uint offset)
-{
- int count;
- u16 chan;
- u16 reg[5];
- u8 data[5];
-
- chan = PMICADDR0 + offset;
- for (count = 0; count <= 3; count++) {
- reg[count] = chan++;
- data[count] = MRST_TS_CHAN10 + count;
- }
- reg[count] = chan;
- data[count] = END_OF_CHANNEL;
-
- return intel_scu_ipc_writev(reg, data, 5);
-}
-
-/* Initialize ADC */
-static int mrstouch_adc_init(struct mrstouch_dev *tsdev)
-{
- int err, start;
- u8 ra, rm;
-
- err = mrstouch_pmic_id(&tsdev->vendor, &tsdev->rev);
- if (err) {
- dev_err(&tsdev->spi->dev, "Unable to read PMIC id\n");
- return err;
- }
-
- start = mrstouch_chan_parse(tsdev);
- if (start < 0) {
- dev_err(&tsdev->spi->dev, "Unable to parse channels\n");
- return start;
- }
-
- tsdev->asr = start;
-
- mrstouch_debug("Channel offset(%d): 0x%X\n", tsdev->asr, tsdev->vendor);
-
- /* ADC power on, start, enable PENDET and set loop delay
- * ADC loop delay is set to 4.5 ms approximately
- * Loop delay more than this results in jitter in adc readings
- * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
- * interrupt generation sometimes.
- */
-
- if (tsdev->vendor == PMIC_VENDOR_FS) {
- ra = 0xE0 | ADC_LOOP_DELAY0;
- rm = 0x5;
- } else {
- /* NEC and MAXIm not consistent with loop delay 0 */
- ra = 0xE0 | ADC_LOOP_DELAY1;
- rm = 0x0;
-
- /* configure touch screen channels */
- err = mrstouch_ts_chan_set(tsdev->asr);
- if (err)
- return err;
- }
- err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
- if (err == 0)
- err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
- return err;
-}
-
-/* Reports x,y coordinates to event subsystem */
-static void mrstouch_report_xy(struct mrstouch_dev *tsdev, u16 x, u16 y, u16 z)
-{
- int xdiff, ydiff;
-
- if (tsdev->pendown && z <= TOUCH_PRESSURE) {
- /* Pen removed, report button release */
- mrstouch_debug("BTN REL(%d)", z);
- input_report_key(tsdev->input, BTN_TOUCH, 0);
- tsdev->pendown = false;
- }
-
- xdiff = abs(x - tsdev->x);
- ydiff = abs(y - tsdev->y);
-
- /*
- if x and y values changes for XYMOVE_CNT readings it is considered
- as stylus is moving. This is required to differentiate between stylus
- movement and jitter
- */
- if (x < MIN_X || x > MAX_X || y < MIN_Y || y > MAX_Y) {
- /* Spurious values, release button if touched and return */
- if (tsdev->pendown) {
- mrstouch_debug("BTN REL(%d)", z);
- input_report_key(tsdev->input, BTN_TOUCH, 0);
- tsdev->pendown = false;
- }
- return;
- } else if (xdiff >= XMOVE_LIMIT || ydiff >= YMOVE_LIMIT) {
- tsdev->x = x;
- tsdev->y = y;
-
- input_report_abs(tsdev->input, ABS_X, x);
- input_report_abs(tsdev->input, ABS_Y, y);
- input_sync(tsdev->input);
- }
-
-
- if (!tsdev->pendown && z > TOUCH_PRESSURE) {
- /* Pen touched, report button touch */
- mrstouch_debug("BTN TCH(%d, %d, %d)", x, y, z);
- input_report_key(tsdev->input, BTN_TOUCH, 1);
- tsdev->pendown = true;
- }
-}
-
-
-/* Utility to start ADC, used by freescale handler */
-static int pendet_mask(void)
-{
- return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
-}
-
-/* Utility to stop ADC, used by freescale handler */
-static int pendet_umask(void)
-{
- return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
-}
-
-/* Utility to read ADC, used by freescale handler */
-static int mrstouch_pmic_fs_adc_read(struct mrstouch_dev *tsdev)
-{
- int err;
- u16 x, y, z, result;
- u16 reg[4];
- u8 data[4];
-
- result = PMIC_REG_ADCSNS0H + tsdev->asr;
-
- reg[0] = result + 4;
- reg[1] = result + 5;
- reg[2] = result + 16;
- reg[3] = result + 17;
-
- err = intel_scu_ipc_readv(reg, data, 4);
- if (err)
- goto ipc_error;
-
- x = data[0] << 3; /* Higher 7 bits */
- x |= data[1] & 0x7; /* Lower 3 bits */
- x &= 0x3FF;
-
- y = data[2] << 3; /* Higher 7 bits */
- y |= data[3] & 0x7; /* Lower 3 bits */
- y &= 0x3FF;
-
- /* Read Z value */
- reg[0] = result + 28;
- reg[1] = result + 29;
-
- err = intel_scu_ipc_readv(reg, data, 4);
- if (err)
- goto ipc_error;
-
- z = data[0] << 3; /* Higher 7 bits */
- z |= data[1] & 0x7; /* Lower 3 bits */
- z &= 0x3FF;
-
-#if defined(MRSTOUCH_PRINT_XYZP)
- mrstouch_debug("X: %d, Y: %d, Z: %d", x, y, z);
-#endif
-
- if (z >= TOUCH_PRESSURE_FS) {
- mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE - 1); /* Pen Removed */
- return TOUCH_PRESSURE - 1;
- } else {
- mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE + 1); /* Pen Touched */
- return TOUCH_PRESSURE + 1;
- }
-
- return 0;
-
-ipc_error:
- dev_err(&tsdev->spi->dev, "ipc error during fs_adc read\n");
- return err;
-}
-
-/* To handle free scale pmic pendet interrupt */
-static int pmic0_pendet(void *dev_id)
-{
- int err, count;
- u16 chan;
- unsigned int touched;
- struct mrstouch_dev *tsdev = (struct mrstouch_dev *)dev_id;
- u16 reg[5];
- u8 data[5];
-
- chan = PMICADDR0 + tsdev->asr;
-
- /* Set X BIAS */
- for (count = 0; count <= 3; count++) {
- reg[count] = chan++;
- data[count] = 0x2A;
- }
- reg[count] = chan++; /* Dummy */
- data[count] = 0;
-
- err = intel_scu_ipc_writev(reg, data, 5);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /* Set Y BIAS */
- for (count = 0; count <= 3; count++) {
- reg[count] = chan++;
- data[count] = 0x4A;
- }
- reg[count] = chan++; /* Dummy */
- data[count] = 0;
-
- err = intel_scu_ipc_writev(reg, data, 5);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /* Set Z BIAS */
- err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /*Read touch screen channels till pen removed
- * Freescale reports constant value of z for all points
- * z is high when screen is not touched and low when touched
- * Map high z value to not touched and low z value to pen touched
- */
- touched = mrstouch_pmic_fs_adc_read(tsdev);
- while (touched > TOUCH_PRESSURE) {
- touched = mrstouch_pmic_fs_adc_read(tsdev);
- msleep(WAIT_ADC_COMPLETION);
- }
-
- /* Clear all TS channels */
- chan = PMICADDR0 + tsdev->asr;
- for (count = 0; count <= 4; count++) {
- reg[count] = chan++;
- data[count] = 0;
- }
- err = intel_scu_ipc_writev(reg, data, 5);
- if (err)
- goto ipc_error;
-
- for (count = 0; count <= 4; count++) {
- reg[count] = chan++;
- data[count] = 0;
- }
- err = intel_scu_ipc_writev(reg, data, 5);
- if (err)
- goto ipc_error;
-
- err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000);
- if (err)
- goto ipc_error;
-
- return 0;
-
-ipc_error:
- dev_err(&tsdev->spi->dev, "ipc error during pendet\n");
- return err;
-}
-
-
-/* To enable X, Y and Z bias values
- * Enables YPYM for X channels and XPXM for Y channels
- */
-static int mrstouch_ts_bias_set(uint offset, uint bias)
-{
- int count;
- u16 chan, start;
- u16 reg[4];
- u8 data[4];
-
- chan = PMICADDR0 + offset;
- start = MRST_TS_CHAN10;
-
- for (count = 0; count <= 3; count++) {
- reg[count] = chan++;
- data[count] = bias | (start + count);
- }
- return intel_scu_ipc_writev(reg, data, 4);
-}
-
-/* To read touch screen channel values */
-static int mrstouch_adc_read(struct mrstouch_dev *tsdev)
-{
- int err;
- u16 xp, xm, yp, ym, zp, zm;
-
- /* configure Y bias for X channels */
- err = mrstouch_ts_bias_set(tsdev->asr, YBIAS);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /* read x+ and x- channels */
- err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &xp, &xm);
- if (err)
- goto ipc_error;
-
- /* configure x bias for y channels */
- err = mrstouch_ts_bias_set(tsdev->asr, XBIAS);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /* read y+ and y- channels */
- err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, &yp, &ym);
- if (err)
- goto ipc_error;
-
- /* configure z bias for x and y channels */
- err = mrstouch_ts_bias_set(tsdev->asr, ZBIAS);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /* read z+ and z- channels */
- err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &zp, &zm);
- if (err)
- goto ipc_error;
-
-#if defined(MRSTOUCH_PRINT_XYZP)
- printk(KERN_INFO "X+: %d, Y+: %d, Z+: %d\n", xp, yp, zp);
-#endif
-
-#if defined(MRSTOUCH_PRINT_XYZM)
- printk(KERN_INFO "X-: %d, Y-: %d, Z-: %d\n", xm, ym, zm);
-#endif
-
- mrstouch_report_xy(tsdev, xp, yp, zp); /* report x and y to eventX */
-
- return zp;
-
-ipc_error:
- dev_err(&tsdev->spi->dev, "ipc error during adc read\n");
- return err;
-}
-
-/* PENDET interrupt handler function for NEC and MAXIM */
-static void pmic12_pendet(void *data)
-{
- unsigned int touched;
- struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
-
- /* read touch screen channels till pen removed */
- do {
- touched = mrstouch_adc_read(tsdev);
- } while (touched > TOUCH_PRESSURE);
-}
-
-/* Handler to process PENDET interrupt */
-int mrstouch_pendet(void *data)
-{
- struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
- while (1) {
- /* Wait for PENDET interrupt */
- if (mutex_lock_interruptible(&tsdev->lock)) {
- msleep(WAIT_ADC_COMPLETION);
- continue;
- }
-
- if (tsdev->busy)
- return 0;
-
- tsdev->busy = true;
-
- if (tsdev->vendor == PMIC_VENDOR_NEC ||
- tsdev->vendor == PMIC_VENDOR_MAXIM) {
- /* PENDET must be disabled in NEC before reading ADC */
- pendet_enable(tsdev,false); /* Disbale PENDET */
- pmic12_pendet(tsdev);
- pendet_enable(tsdev, true); /*Enable PENDET */
- } else if (tsdev->vendor == PMIC_VENDOR_FS) {
- pendet_umask(); /* Stop ADC */
- pmic0_pendet(tsdev);
- pendet_mask(); /* Stop ADC */
- } else
- dev_err(&tsdev->spi->dev, "Unsupported touchscreen: %d\n",
- tsdev->vendor);
-
- tsdev->busy = false;
-
- }
- return 0;
-}
-
-/* PENDET interrupt handler */
-static irqreturn_t pendet_intr_handler(int irq, void *handle)
-{
- struct mrstouch_dev *tsdev = (struct mrstouch_dev *)handle;
-
- mutex_unlock(&tsdev->lock);
- return IRQ_HANDLED;
-}
-
-/* Intializes input device and registers with input subsystem */
-static int ts_input_dev_init(struct mrstouch_dev *tsdev, struct spi_device *spi)
-{
- int err = 0;
-
- mrstouch_debug("%s", __func__);
-
- tsdev->input = input_allocate_device();
- if (!tsdev->input) {
- dev_err(&tsdev->spi->dev, "Unable to allocate input device.\n");
- return -EINVAL;
- }
-
- tsdev->input->name = "mrst_touchscreen";
- snprintf(tsdev->phys, sizeof(tsdev->phys),
- "%s/input0", dev_name(&spi->dev));
- tsdev->input->phys = tsdev->phys;
- tsdev->input->dev.parent = &spi->dev;
-
- tsdev->input->id.vendor = tsdev->vendor;
- tsdev->input->id.version = tsdev->rev;
-
- tsdev->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- tsdev->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
- input_set_abs_params(tsdev->input, ABS_X, MIN_X, MIN_Y, 0, 0);
- input_set_abs_params(tsdev->input, ABS_Y, MIN_X, MIN_Y, 0, 0);
-
- err = input_register_device(tsdev->input);
- if (err) {
- dev_err(&tsdev->spi->dev, "unable to register input device\n");
- input_free_device(tsdev->input);
- return err;
- }
-
- mrstouch_debug("%s", "mrstouch initialized");
-
- return 0;
-
-}
-
-/* Probe function for touch screen driver */
-static int __devinit mrstouch_probe(struct spi_device *mrstouch_spi)
-{
- int err;
- unsigned int myirq;
- struct mrstouch_dev *tsdev;
-
- mrstouch_debug("%s(%p)", __func__, mrstouch_spi);
-
- mrstouchdevp = NULL;
- myirq = mrstouch_spi->irq;
-
- if (!mrstouch_spi->irq) {
- dev_err(&mrstouch_spi->dev, "no interrupt assigned\n");
- return -EINVAL;
- }
-
- tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
- if (!tsdev) {
- dev_err(&mrstouch_spi->dev, "unable to allocate memory\n");
- return -ENOMEM;
- }
-
- tsdev->irq = myirq;
- mrstouchdevp = tsdev;
-
- err = mrstouch_adc_init(tsdev);
- if (err) {
- dev_err(&mrstouch_spi->dev, "ADC init failed\n");
- goto mrstouch_err_free_mem;
- }
-
- dev_set_drvdata(&mrstouch_spi->dev, tsdev);
- tsdev->spi = mrstouch_spi;
-
- err = ts_input_dev_init(tsdev, mrstouch_spi);
- if (err) {
- dev_err(&tsdev->spi->dev, "ts_input_dev_init failed");
- goto mrstouch_err_free_mem;
- }
-
- mutex_init(&tsdev->lock);
- mutex_lock(&tsdev->lock)
-
- mrstouch_debug("Requesting IRQ-%d", myirq);
- err = request_irq(myirq, pendet_intr_handler,
- 0, "mrstouch", tsdev);
- if (err) {
- dev_err(&tsdev->spi->dev, "unable to allocate irq\n");
- goto mrstouch_err_free_mem;
- }
-
- tsdev->pendet_thrd = kthread_run(mrstouch_pendet,
- (void *)tsdev, "pendet handler");
- if (IS_ERR(tsdev->pendet_thrd)) {
- dev_err(&tsdev->spi->dev, "kthread_run failed\n");
- err = PTR_ERR(tsdev->pendet_thrd);
- goto mrstouch_err_free_mem;
- }
- mrstouch_debug("%s", "Driver initialized");
- return 0;
-
-mrstouch_err_free_mem:
- kfree(tsdev);
- return err;
-}
-
-static int mrstouch_suspend(struct spi_device *spi, pm_message_t msg)
-{
- mrstouch_debug("%s", __func__);
- mrstouchdevp->suspended = 1;
- return 0;
-}
-
-static int mrstouch_resume(struct spi_device *spi)
-{
- mrstouch_debug("%s", __func__);
- mrstouchdevp->suspended = 0;
- return 0;
-}
-
-static int mrstouch_remove(struct spi_device *spi)
-{
- mrstouch_debug("%s", __func__);
- free_irq(mrstouchdevp->irq, mrstouchdevp);
- input_unregister_device(mrstouchdevp->input);
- input_free_device(mrstouchdevp->input);
- if (mrstouchdevp->pendet_thrd)
- kthread_stop(mrstouchdevp->pendet_thrd);
- kfree(mrstouchdevp);
- return 0;
-}
-
-static struct spi_driver mrstouch_driver = {
- .driver = {
- .name = "pmic_touch",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = mrstouch_probe,
- .suspend = mrstouch_suspend,
- .resume = mrstouch_resume,
- .remove = mrstouch_remove,
-};
-
-static int __init mrstouch_module_init(void)
-{
- int err;
-
- mrstouch_debug("%s", __func__);
- err = spi_register_driver(&mrstouch_driver);
- if (err) {
- mrstouch_debug("%s(%d)", "SPI PENDET failed", err);
- return -1;
- }
-
- return 0;
-}
-
-static void __exit mrstouch_module_exit(void)
-{
- mrstouch_debug("%s", __func__);
- spi_unregister_driver(&mrstouch_driver);
- return;
-}
-
-module_init(mrstouch_module_init);
-module_exit(mrstouch_module_exit);
-
-MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
-MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 77be3c24a427..3076b1cc05df 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2397,7 +2397,7 @@ static const struct dev_pm_ops r8a66597_dev_pm_ops = {
#define R8A66597_DEV_PM_OPS NULL
#endif
-static int __init_or_module r8a66597_remove(struct platform_device *pdev)
+static int __devexit r8a66597_remove(struct platform_device *pdev)
{
struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@@ -2542,7 +2542,7 @@ clean_up:
static struct platform_driver r8a66597_driver = {
.probe = r8a66597_probe,
- .remove = r8a66597_remove,
+ .remove = __devexit_p(r8a66597_remove),
.driver = {
.name = (char *) hcd_name,
.owner = THIS_MODULE,
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index f8d69ad36830..5bf91236c701 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2970,7 +2970,8 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
struct atyfb_par *par = info->par;
struct device_node *dp;
char prop[128];
- int node, len, i, j, ret;
+ phandle node;
+ int len, i, j, ret;
u32 mem, chip_id;
/*
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index d72075a9f01c..7a1419279c8f 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1243,8 +1243,10 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
if (priv->ch[i].sglist)
vfree(priv->ch[i].sglist);
- dma_free_coherent(&pdev->dev, info->fix.smem_len,
- info->screen_base, priv->ch[i].dma_handle);
+ if (info->screen_base)
+ dma_free_coherent(&pdev->dev, info->fix.smem_len,
+ info->screen_base,
+ priv->ch[i].dma_handle);
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
}
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index a5bf5771a22a..9060f08e70cf 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -17,6 +17,7 @@
#include <linux/string.h>
#include <linux/list.h>
#include <linux/sched.h>
+#include <linux/spinlock.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
@@ -31,19 +32,23 @@ void coda_cache_enter(struct inode *inode, int mask)
{
struct coda_inode_info *cii = ITOC(inode);
+ spin_lock(&cii->c_lock);
cii->c_cached_epoch = atomic_read(&permission_epoch);
if (cii->c_uid != current_fsuid()) {
cii->c_uid = current_fsuid();
cii->c_cached_perm = mask;
} else
cii->c_cached_perm |= mask;
+ spin_unlock(&cii->c_lock);
}
/* remove cached acl from an inode */
void coda_cache_clear_inode(struct inode *inode)
{
struct coda_inode_info *cii = ITOC(inode);
+ spin_lock(&cii->c_lock);
cii->c_cached_epoch = atomic_read(&permission_epoch) - 1;
+ spin_unlock(&cii->c_lock);
}
/* remove all acl caches */
@@ -57,13 +62,15 @@ void coda_cache_clear_all(struct super_block *sb)
int coda_cache_check(struct inode *inode, int mask)
{
struct coda_inode_info *cii = ITOC(inode);
- int hit;
+ int hit;
- hit = (mask & cii->c_cached_perm) == mask &&
- cii->c_uid == current_fsuid() &&
- cii->c_cached_epoch == atomic_read(&permission_epoch);
+ spin_lock(&cii->c_lock);
+ hit = (mask & cii->c_cached_perm) == mask &&
+ cii->c_uid == current_fsuid() &&
+ cii->c_cached_epoch == atomic_read(&permission_epoch);
+ spin_unlock(&cii->c_lock);
- return hit;
+ return hit;
}
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index a7a780929eec..602240569c89 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -45,13 +45,15 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
static int coda_test_inode(struct inode *inode, void *data)
{
struct CodaFid *fid = (struct CodaFid *)data;
- return coda_fideq(&(ITOC(inode)->c_fid), fid);
+ struct coda_inode_info *cii = ITOC(inode);
+ return coda_fideq(&cii->c_fid, fid);
}
static int coda_set_inode(struct inode *inode, void *data)
{
struct CodaFid *fid = (struct CodaFid *)data;
- ITOC(inode)->c_fid = *fid;
+ struct coda_inode_info *cii = ITOC(inode);
+ cii->c_fid = *fid;
return 0;
}
@@ -71,6 +73,7 @@ struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
cii = ITOC(inode);
/* we still need to set i_ino for things like stat(2) */
inode->i_ino = hash;
+ /* inode is locked and unique, no need to grab cii->c_lock */
cii->c_mapcount = 0;
unlock_new_inode(inode);
}
@@ -107,14 +110,20 @@ int coda_cnode_make(struct inode **inode, struct CodaFid *fid, struct super_bloc
}
+/* Although we treat Coda file identifiers as immutable, there is one
+ * special case for files created during a disconnection where they may
+ * not be globally unique. When an identifier collision is detected we
+ * first try to flush the cached inode from the kernel and finally
+ * resort to renaming/rehashing in-place. Userspace remembers both old
+ * and new values of the identifier to handle any in-flight upcalls.
+ * The real solution is to use globally unique UUIDs as identifiers, but
+ * retrofitting the existing userspace code for this is non-trivial. */
void coda_replace_fid(struct inode *inode, struct CodaFid *oldfid,
struct CodaFid *newfid)
{
- struct coda_inode_info *cii;
+ struct coda_inode_info *cii = ITOC(inode);
unsigned long hash = coda_f2i(newfid);
- cii = ITOC(inode);
-
BUG_ON(!coda_fideq(&cii->c_fid, oldfid));
/* replace fid and rehash inode */
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index ccd98b0f2b0b..96fbeab77f2f 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -17,7 +17,7 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
@@ -116,15 +116,11 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc
goto exit;
}
- lock_kernel();
-
error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
&type, &resfid);
if (!error)
error = coda_cnode_make(&inode, &resfid, dir->i_sb);
- unlock_kernel();
-
if (error && error != -ENOENT)
return ERR_PTR(error);
@@ -140,28 +136,24 @@ exit:
int coda_permission(struct inode *inode, int mask)
{
- int error = 0;
+ int error;
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
if (!mask)
- return 0;
+ return 0;
if ((mask & MAY_EXEC) && !execute_ok(inode))
return -EACCES;
- lock_kernel();
-
if (coda_cache_check(inode, mask))
- goto out;
+ return 0;
- error = venus_access(inode->i_sb, coda_i2f(inode), mask);
+ error = venus_access(inode->i_sb, coda_i2f(inode), mask);
if (!error)
coda_cache_enter(inode, mask);
- out:
- unlock_kernel();
return error;
}
@@ -200,41 +192,34 @@ static inline void coda_dir_drop_nlink(struct inode *dir)
/* creation routines: create, mknod, mkdir, link, symlink */
static int coda_create(struct inode *dir, struct dentry *de, int mode, struct nameidata *nd)
{
- int error=0;
+ int error;
const char *name=de->d_name.name;
int length=de->d_name.len;
struct inode *inode;
struct CodaFid newfid;
struct coda_vattr attrs;
- lock_kernel();
-
- if (coda_isroot(dir) && coda_iscontrol(name, length)) {
- unlock_kernel();
+ if (coda_isroot(dir) && coda_iscontrol(name, length))
return -EPERM;
- }
error = venus_create(dir->i_sb, coda_i2f(dir), name, length,
0, mode, &newfid, &attrs);
-
- if ( error ) {
- unlock_kernel();
- d_drop(de);
- return error;
- }
+ if (error)
+ goto err_out;
inode = coda_iget(dir->i_sb, &newfid, &attrs);
- if ( IS_ERR(inode) ) {
- unlock_kernel();
- d_drop(de);
- return PTR_ERR(inode);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ goto err_out;
}
/* invalidate the directory cnode's attributes */
coda_dir_update_mtime(dir);
- unlock_kernel();
d_instantiate(de, inode);
return 0;
+err_out:
+ d_drop(de);
+ return error;
}
static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
@@ -246,36 +231,29 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
int error;
struct CodaFid newfid;
- lock_kernel();
-
- if (coda_isroot(dir) && coda_iscontrol(name, len)) {
- unlock_kernel();
+ if (coda_isroot(dir) && coda_iscontrol(name, len))
return -EPERM;
- }
attrs.va_mode = mode;
error = venus_mkdir(dir->i_sb, coda_i2f(dir),
name, len, &newfid, &attrs);
-
- if ( error ) {
- unlock_kernel();
- d_drop(de);
- return error;
- }
+ if (error)
+ goto err_out;
inode = coda_iget(dir->i_sb, &newfid, &attrs);
- if ( IS_ERR(inode) ) {
- unlock_kernel();
- d_drop(de);
- return PTR_ERR(inode);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ goto err_out;
}
/* invalidate the directory cnode's attributes */
coda_dir_inc_nlink(dir);
coda_dir_update_mtime(dir);
- unlock_kernel();
d_instantiate(de, inode);
return 0;
+err_out:
+ d_drop(de);
+ return error;
}
/* try to make de an entry in dir_inodde linked to source_de */
@@ -287,52 +265,38 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
int len = de->d_name.len;
int error;
- lock_kernel();
-
- if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
- unlock_kernel();
+ if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
- }
error = venus_link(dir_inode->i_sb, coda_i2f(inode),
coda_i2f(dir_inode), (const char *)name, len);
-
if (error) {
d_drop(de);
- goto out;
+ return error;
}
coda_dir_update_mtime(dir_inode);
atomic_inc(&inode->i_count);
d_instantiate(de, inode);
inc_nlink(inode);
-
-out:
- unlock_kernel();
- return(error);
+ return 0;
}
static int coda_symlink(struct inode *dir_inode, struct dentry *de,
const char *symname)
{
- const char *name = de->d_name.name;
+ const char *name = de->d_name.name;
int len = de->d_name.len;
int symlen;
- int error = 0;
-
- lock_kernel();
+ int error;
- if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
- unlock_kernel();
+ if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
- }
symlen = strlen(symname);
- if ( symlen > CODA_MAXPATHLEN ) {
- unlock_kernel();
+ if (symlen > CODA_MAXPATHLEN)
return -ENAMETOOLONG;
- }
/*
* This entry is now negative. Since we do not create
@@ -343,10 +307,9 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
symname, symlen);
/* mtime is no good anymore */
- if ( !error )
+ if (!error)
coda_dir_update_mtime(dir_inode);
- unlock_kernel();
return error;
}
@@ -357,17 +320,12 @@ static int coda_unlink(struct inode *dir, struct dentry *de)
const char *name = de->d_name.name;
int len = de->d_name.len;
- lock_kernel();
-
error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
- if ( error ) {
- unlock_kernel();
+ if (error)
return error;
- }
coda_dir_update_mtime(dir);
drop_nlink(de->d_inode);
- unlock_kernel();
return 0;
}
@@ -377,8 +335,6 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
int len = de->d_name.len;
int error;
- lock_kernel();
-
error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
if (!error) {
/* VFS may delete the child */
@@ -389,7 +345,6 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
coda_dir_drop_nlink(dir);
coda_dir_update_mtime(dir);
}
- unlock_kernel();
return error;
}
@@ -403,15 +358,12 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
int new_length = new_dentry->d_name.len;
int error;
- lock_kernel();
-
error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
coda_i2f(new_dir), old_length, new_length,
(const char *) old_name, (const char *)new_name);
-
- if ( !error ) {
- if ( new_dentry->d_inode ) {
- if ( S_ISDIR(new_dentry->d_inode->i_mode) ) {
+ if (!error) {
+ if (new_dentry->d_inode) {
+ if (S_ISDIR(new_dentry->d_inode->i_mode)) {
coda_dir_drop_nlink(old_dir);
coda_dir_inc_nlink(new_dir);
}
@@ -423,8 +375,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
coda_flag_inode(new_dir, C_VATTR);
}
}
- unlock_kernel();
-
return error;
}
@@ -594,10 +544,7 @@ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
struct inode *inode = de->d_inode;
struct coda_inode_info *cii;
- if (!inode)
- return 1;
- lock_kernel();
- if (coda_isroot(inode))
+ if (!inode || coda_isroot(inode))
goto out;
if (is_bad_inode(inode))
goto bad;
@@ -617,13 +564,12 @@ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
goto out;
/* clear the flags. */
+ spin_lock(&cii->c_lock);
cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
-
+ spin_unlock(&cii->c_lock);
bad:
- unlock_kernel();
return 0;
out:
- unlock_kernel();
return 1;
}
@@ -656,20 +602,19 @@ static int coda_dentry_delete(struct dentry * dentry)
int coda_revalidate_inode(struct dentry *dentry)
{
struct coda_vattr attr;
- int error = 0;
+ int error;
int old_mode;
ino_t old_ino;
struct inode *inode = dentry->d_inode;
struct coda_inode_info *cii = ITOC(inode);
- lock_kernel();
- if ( !cii->c_flags )
- goto ok;
+ if (!cii->c_flags)
+ return 0;
if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
- if ( error )
- goto return_bad;
+ if (error)
+ return -EIO;
/* this inode may be lost if:
- it's ino changed
@@ -688,17 +633,13 @@ int coda_revalidate_inode(struct dentry *dentry)
/* the following can happen when a local fid is replaced
with a global one, here we lose and declare the inode bad */
if (inode->i_ino != old_ino)
- goto return_bad;
+ return -EIO;
coda_flag_inode_children(inode, C_FLUSH);
+
+ spin_lock(&cii->c_lock);
cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
+ spin_unlock(&cii->c_lock);
}
-
-ok:
- unlock_kernel();
return 0;
-
-return_bad:
- unlock_kernel();
- return -EIO;
}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index ad3cd2abeeb4..c8b50ba4366a 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -15,7 +15,7 @@
#include <linux/stat.h>
#include <linux/cred.h>
#include <linux/errno.h>
-#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
@@ -109,19 +109,24 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
coda_inode = coda_file->f_path.dentry->d_inode;
host_inode = host_file->f_path.dentry->d_inode;
+
+ cii = ITOC(coda_inode);
+ spin_lock(&cii->c_lock);
coda_file->f_mapping = host_file->f_mapping;
if (coda_inode->i_mapping == &coda_inode->i_data)
coda_inode->i_mapping = host_inode->i_mapping;
/* only allow additional mmaps as long as userspace isn't changing
* the container file on us! */
- else if (coda_inode->i_mapping != host_inode->i_mapping)
+ else if (coda_inode->i_mapping != host_inode->i_mapping) {
+ spin_unlock(&cii->c_lock);
return -EBUSY;
+ }
/* keep track of how often the coda_inode/host_file has been mmapped */
- cii = ITOC(coda_inode);
cii->c_mapcount++;
cfi->cfi_mapcount++;
+ spin_unlock(&cii->c_lock);
return host_file->f_op->mmap(host_file, vma);
}
@@ -138,8 +143,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
if (!cfi)
return -ENOMEM;
- lock_kernel();
-
error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
&host_file);
if (!host_file)
@@ -147,7 +150,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
if (error) {
kfree(cfi);
- unlock_kernel();
return error;
}
@@ -159,8 +161,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
BUG_ON(coda_file->private_data != NULL);
coda_file->private_data = cfi;
-
- unlock_kernel();
return 0;
}
@@ -171,9 +171,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
struct coda_file_info *cfi;
struct coda_inode_info *cii;
struct inode *host_inode;
- int err = 0;
-
- lock_kernel();
+ int err;
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
@@ -185,18 +183,18 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
cii = ITOC(coda_inode);
/* did we mmap this file? */
+ spin_lock(&cii->c_lock);
if (coda_inode->i_mapping == &host_inode->i_data) {
cii->c_mapcount -= cfi->cfi_mapcount;
if (!cii->c_mapcount)
coda_inode->i_mapping = &coda_inode->i_data;
}
+ spin_unlock(&cii->c_lock);
fput(cfi->cfi_container);
kfree(coda_file->private_data);
coda_file->private_data = NULL;
- unlock_kernel();
-
/* VFS fput ignores the return value from file_operations->release, so
* there is no use returning an error here */
return 0;
@@ -207,7 +205,7 @@ int coda_fsync(struct file *coda_file, int datasync)
struct file *host_file;
struct inode *coda_inode = coda_file->f_path.dentry->d_inode;
struct coda_file_info *cfi;
- int err = 0;
+ int err;
if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
S_ISLNK(coda_inode->i_mode)))
@@ -218,11 +216,8 @@ int coda_fsync(struct file *coda_file, int datasync)
host_file = cfi->cfi_container;
err = vfs_fsync(host_file, datasync);
- if ( !err && !datasync ) {
- lock_kernel();
+ if (!err && !datasync)
err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
- unlock_kernel();
- }
return err;
}
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index bfe8179b1295..7993b96ca348 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -15,7 +15,8 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/unistd.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
#include <linux/file.h>
#include <linux/vfs.h>
#include <linux/slab.h>
@@ -51,6 +52,7 @@ static struct inode *coda_alloc_inode(struct super_block *sb)
ei->c_flags = 0;
ei->c_uid = 0;
ei->c_cached_perm = 0;
+ spin_lock_init(&ei->c_lock);
return &ei->vfs_inode;
}
@@ -143,13 +145,11 @@ static int get_device_index(struct coda_mount_data *data)
static int coda_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *root = NULL;
- struct venus_comm *vc = NULL;
+ struct venus_comm *vc;
struct CodaFid fid;
int error;
int idx;
- lock_kernel();
-
idx = get_device_index((struct coda_mount_data *) data);
/* Ignore errors in data, for backward compatibility */
@@ -159,23 +159,26 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
printk(KERN_INFO "coda_read_super: device index: %i\n", idx);
vc = &coda_comms[idx];
+ mutex_lock(&vc->vc_mutex);
+
if (!vc->vc_inuse) {
printk("coda_read_super: No pseudo device\n");
- unlock_kernel();
- return -EINVAL;
+ error = -EINVAL;
+ goto unlock_out;
}
- if ( vc->vc_sb ) {
+ if (vc->vc_sb) {
printk("coda_read_super: Device already mounted\n");
- unlock_kernel();
- return -EBUSY;
+ error = -EBUSY;
+ goto unlock_out;
}
error = bdi_setup_and_register(&vc->bdi, "coda", BDI_CAP_MAP_COPY);
if (error)
- goto bdi_err;
+ goto unlock_out;
vc->vc_sb = sb;
+ mutex_unlock(&vc->vc_mutex);
sb->s_fs_info = vc;
sb->s_flags |= MS_NOATIME;
@@ -204,28 +207,33 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
printk("coda_read_super: rootinode is %ld dev %s\n",
root->i_ino, root->i_sb->s_id);
sb->s_root = d_alloc_root(root);
- if (!sb->s_root)
+ if (!sb->s_root) {
+ error = -EINVAL;
goto error;
- unlock_kernel();
+ }
return 0;
- error:
- bdi_destroy(&vc->bdi);
- bdi_err:
+error:
if (root)
iput(root);
- if (vc)
- vc->vc_sb = NULL;
- unlock_kernel();
- return -EINVAL;
+ mutex_lock(&vc->vc_mutex);
+ bdi_destroy(&vc->bdi);
+ vc->vc_sb = NULL;
+ sb->s_fs_info = NULL;
+unlock_out:
+ mutex_unlock(&vc->vc_mutex);
+ return error;
}
static void coda_put_super(struct super_block *sb)
{
- bdi_destroy(&coda_vcp(sb)->bdi);
- coda_vcp(sb)->vc_sb = NULL;
+ struct venus_comm *vcp = coda_vcp(sb);
+ mutex_lock(&vcp->vc_mutex);
+ bdi_destroy(&vcp->bdi);
+ vcp->vc_sb = NULL;
sb->s_fs_info = NULL;
+ mutex_unlock(&vcp->vc_mutex);
printk("Coda: Bye bye.\n");
}
@@ -251,8 +259,6 @@ int coda_setattr(struct dentry *de, struct iattr *iattr)
struct coda_vattr vattr;
int error;
- lock_kernel();
-
memset(&vattr, 0, sizeof(vattr));
inode->i_ctime = CURRENT_TIME_SEC;
@@ -262,13 +268,10 @@ int coda_setattr(struct dentry *de, struct iattr *iattr)
/* Venus is responsible for truncating the container-file!!! */
error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
- if ( !error ) {
+ if (!error) {
coda_vattr_to_iattr(inode, &vattr);
coda_cache_clear_inode(inode);
}
-
- unlock_kernel();
-
return error;
}
@@ -282,12 +285,8 @@ static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int error;
- lock_kernel();
-
error = venus_statfs(dentry, buf);
- unlock_kernel();
-
if (error) {
/* fake something like AFS does */
buf->f_blocks = 9000000;
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 028a9a0f588b..2fd89b5c5c7b 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -23,8 +23,6 @@
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
-#include <linux/smp_lock.h>
-
/* pioctl ops */
static int coda_ioctl_permission(struct inode *inode, int mask);
static long coda_pioctl(struct file *filp, unsigned int cmd,
@@ -58,13 +56,9 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
struct inode *target_inode = NULL;
struct coda_inode_info *cnp;
- lock_kernel();
-
/* get the Pioctl data arguments from user space */
- if (copy_from_user(&data, (void __user *)user_data, sizeof(data))) {
- error = -EINVAL;
- goto out;
- }
+ if (copy_from_user(&data, (void __user *)user_data, sizeof(data)))
+ return -EINVAL;
/*
* Look up the pathname. Note that the pathname is in
@@ -76,13 +70,12 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
error = user_lpath(data.path, &path);
if (error)
- goto out;
- else
- target_inode = path.dentry->d_inode;
+ return error;
+
+ target_inode = path.dentry->d_inode;
/* return if it is not a Coda inode */
if (target_inode->i_sb != inode->i_sb) {
- path_put(&path);
error = -EINVAL;
goto out;
}
@@ -91,10 +84,7 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
cnp = ITOC(target_inode);
error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
-
- path_put(&path);
-
out:
- unlock_kernel();
+ path_put(&path);
return error;
}
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index fdc2f3ef7ecd..62647a8595e4 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -35,7 +35,7 @@
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/list.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -67,8 +67,10 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
unsigned int mask = POLLOUT | POLLWRNORM;
poll_wait(file, &vcp->vc_waitq, wait);
+ mutex_lock(&vcp->vc_mutex);
if (!list_empty(&vcp->vc_pending))
mask |= POLLIN | POLLRDNORM;
+ mutex_unlock(&vcp->vc_mutex);
return mask;
}
@@ -108,16 +110,9 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
return -EFAULT;
if (DOWNCALL(hdr.opcode)) {
- struct super_block *sb = NULL;
- union outputArgs *dcbuf;
+ union outputArgs *dcbuf;
int size = sizeof(*dcbuf);
- sb = vcp->vc_sb;
- if ( !sb ) {
- count = nbytes;
- goto out;
- }
-
if ( nbytes < sizeof(struct coda_out_hdr) ) {
printk("coda_downcall opc %d uniq %d, not enough!\n",
hdr.opcode, hdr.unique);
@@ -137,9 +132,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
}
/* what downcall errors does Venus handle ? */
- lock_kernel();
- error = coda_downcall(hdr.opcode, dcbuf, sb);
- unlock_kernel();
+ error = coda_downcall(vcp, hdr.opcode, dcbuf);
CODA_FREE(dcbuf, nbytes);
if (error) {
@@ -152,7 +145,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
}
/* Look for the message on the processing queue. */
- lock_kernel();
+ mutex_lock(&vcp->vc_mutex);
list_for_each(lh, &vcp->vc_processing) {
tmp = list_entry(lh, struct upc_req , uc_chain);
if (tmp->uc_unique == hdr.unique) {
@@ -161,7 +154,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
break;
}
}
- unlock_kernel();
+ mutex_unlock(&vcp->vc_mutex);
if (!req) {
printk("psdev_write: msg (%d, %d) not found\n",
@@ -216,7 +209,7 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
if (nbytes == 0)
return 0;
- lock_kernel();
+ mutex_lock(&vcp->vc_mutex);
add_wait_queue(&vcp->vc_waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
@@ -230,7 +223,9 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
retval = -ERESTARTSYS;
break;
}
+ mutex_unlock(&vcp->vc_mutex);
schedule();
+ mutex_lock(&vcp->vc_mutex);
}
set_current_state(TASK_RUNNING);
@@ -263,7 +258,7 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
kfree(req);
out:
- unlock_kernel();
+ mutex_unlock(&vcp->vc_mutex);
return (count ? count : retval);
}
@@ -276,10 +271,10 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
if (idx < 0 || idx >= MAX_CODADEVS)
return -ENODEV;
- lock_kernel();
-
err = -EBUSY;
vcp = &coda_comms[idx];
+ mutex_lock(&vcp->vc_mutex);
+
if (!vcp->vc_inuse) {
vcp->vc_inuse++;
@@ -293,7 +288,7 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
err = 0;
}
- unlock_kernel();
+ mutex_unlock(&vcp->vc_mutex);
return err;
}
@@ -308,7 +303,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
return -1;
}
- lock_kernel();
+ mutex_lock(&vcp->vc_mutex);
/* Wakeup clients so they can return. */
list_for_each_entry_safe(req, tmp, &vcp->vc_pending, uc_chain) {
@@ -333,7 +328,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
file->private_data = NULL;
vcp->vc_inuse--;
- unlock_kernel();
+ mutex_unlock(&vcp->vc_mutex);
return 0;
}
@@ -362,9 +357,11 @@ static int init_coda_psdev(void)
err = PTR_ERR(coda_psdev_class);
goto out_chrdev;
}
- for (i = 0; i < MAX_CODADEVS; i++)
+ for (i = 0; i < MAX_CODADEVS; i++) {
+ mutex_init(&(&coda_comms[i])->vc_mutex);
device_create(coda_psdev_class, NULL,
MKDEV(CODA_PSDEV_MAJOR, i), NULL, "cfs%d", i);
+ }
coda_sysctl_init();
goto out;
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index 4513b7258458..af78f007a2b0 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -14,7 +14,6 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
@@ -29,11 +28,9 @@ static int coda_symlink_filler(struct file *file, struct page *page)
unsigned int len = PAGE_SIZE;
char *p = kmap(page);
- lock_kernel();
cii = ITOC(inode);
error = venus_readlink(inode->i_sb, &cii->c_fid, p, &len);
- unlock_kernel();
if (error)
goto fail;
SetPageUptodate(page);
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index b8893ab6f9e6..c3563cab9758 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -27,6 +27,7 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/vfs.h>
@@ -606,7 +607,8 @@ static void coda_unblock_signals(sigset_t *old)
(r)->uc_opcode != CODA_RELEASE) || \
(r)->uc_flags & CODA_REQ_READ))
-static inline void coda_waitfor_upcall(struct upc_req *req)
+static inline void coda_waitfor_upcall(struct venus_comm *vcp,
+ struct upc_req *req)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long timeout = jiffies + coda_timeout * HZ;
@@ -639,10 +641,12 @@ static inline void coda_waitfor_upcall(struct upc_req *req)
break;
}
+ mutex_unlock(&vcp->vc_mutex);
if (blocked)
schedule_timeout(HZ);
else
schedule();
+ mutex_lock(&vcp->vc_mutex);
}
if (blocked)
coda_unblock_signals(&old);
@@ -667,18 +671,23 @@ static int coda_upcall(struct venus_comm *vcp,
{
union outputArgs *out;
union inputArgs *sig_inputArgs;
- struct upc_req *req, *sig_req;
- int error = 0;
+ struct upc_req *req = NULL, *sig_req;
+ int error;
+
+ mutex_lock(&vcp->vc_mutex);
if (!vcp->vc_inuse) {
printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
- return -ENXIO;
+ error = -ENXIO;
+ goto exit;
}
/* Format the request message. */
req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
- if (!req)
- return -ENOMEM;
+ if (!req) {
+ error = -ENOMEM;
+ goto exit;
+ }
req->uc_data = (void *)buffer;
req->uc_flags = 0;
@@ -705,7 +714,7 @@ static int coda_upcall(struct venus_comm *vcp,
* ENODEV. */
/* Go to sleep. Wake up on signals only after the timeout. */
- coda_waitfor_upcall(req);
+ coda_waitfor_upcall(vcp, req);
/* Op went through, interrupt or not... */
if (req->uc_flags & CODA_REQ_WRITE) {
@@ -759,6 +768,7 @@ static int coda_upcall(struct venus_comm *vcp,
exit:
kfree(req);
+ mutex_unlock(&vcp->vc_mutex);
return error;
}
@@ -796,21 +806,24 @@ exit:
*
* CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
-int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
{
struct inode *inode = NULL;
- struct CodaFid *fid, *newfid;
+ struct CodaFid *fid = NULL, *newfid;
+ struct super_block *sb;
/* Handle invalidation requests. */
- if ( !sb || !sb->s_root)
- return 0;
+ mutex_lock(&vcp->vc_mutex);
+ sb = vcp->vc_sb;
+ if (!sb || !sb->s_root)
+ goto unlock_out;
switch (opcode) {
case CODA_FLUSH:
coda_cache_clear_all(sb);
shrink_dcache_sb(sb);
if (sb->s_root->d_inode)
- coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
+ coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
break;
case CODA_PURGEUSER:
@@ -819,45 +832,53 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
case CODA_ZAPDIR:
fid = &out->coda_zapdir.CodaFid;
- inode = coda_fid_to_inode(fid, sb);
- if (inode) {
- coda_flag_inode_children(inode, C_PURGE);
- coda_flag_inode(inode, C_VATTR);
- }
break;
case CODA_ZAPFILE:
fid = &out->coda_zapfile.CodaFid;
- inode = coda_fid_to_inode(fid, sb);
- if (inode)
- coda_flag_inode(inode, C_VATTR);
break;
case CODA_PURGEFID:
fid = &out->coda_purgefid.CodaFid;
+ break;
+
+ case CODA_REPLACE:
+ fid = &out->coda_replace.OldFid;
+ break;
+ }
+ if (fid)
inode = coda_fid_to_inode(fid, sb);
- if (inode) {
- coda_flag_inode_children(inode, C_PURGE);
- /* catch the dentries later if some are still busy */
- coda_flag_inode(inode, C_PURGE);
- d_prune_aliases(inode);
+unlock_out:
+ mutex_unlock(&vcp->vc_mutex);
- }
+ if (!inode)
+ return 0;
+
+ switch (opcode) {
+ case CODA_ZAPDIR:
+ coda_flag_inode_children(inode, C_PURGE);
+ coda_flag_inode(inode, C_VATTR);
+ break;
+
+ case CODA_ZAPFILE:
+ coda_flag_inode(inode, C_VATTR);
+ break;
+
+ case CODA_PURGEFID:
+ coda_flag_inode_children(inode, C_PURGE);
+
+ /* catch the dentries later if some are still busy */
+ coda_flag_inode(inode, C_PURGE);
+ d_prune_aliases(inode);
break;
case CODA_REPLACE:
- fid = &out->coda_replace.OldFid;
newfid = &out->coda_replace.NewFid;
- inode = coda_fid_to_inode(fid, sb);
- if (inode)
- coda_replace_fid(inode, fid, newfid);
+ coda_replace_fid(inode, fid, newfid);
break;
}
-
- if (inode)
- iput(inode);
-
+ iput(inode);
return 0;
}
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index b81bfc016a05..0a8b0ad0c7e2 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -365,25 +365,17 @@ struct device_type part_type = {
static void delete_partition_rcu_cb(struct rcu_head *head)
{
struct hd_struct *part = container_of(head, struct hd_struct, rcu_head);
- struct gendisk *disk = part_to_disk(part);
- struct request_queue *q = disk->queue;
- unsigned long flags;
part->start_sect = 0;
part->nr_sects = 0;
part_stat_set_all(part, 0);
put_device(part_to_dev(part));
-
- spin_lock_irqsave(q->queue_lock, flags);
- elv_quiesce_end(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
}
void delete_partition(struct gendisk *disk, int partno)
{
struct disk_part_tbl *ptbl = disk->part_tbl;
struct hd_struct *part;
- struct request_queue *q = disk->queue;
if (partno >= ptbl->len)
return;
@@ -398,10 +390,6 @@ void delete_partition(struct gendisk *disk, int partno)
kobject_put(part->holder_dir);
device_del(part_to_dev(part));
- spin_lock_irq(q->queue_lock);
- elv_quiesce_start(q);
- spin_unlock_irq(q->queue_lock);
-
call_rcu(&part->rcu_head, delete_partition_rcu_cb);
}
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 009b80e49f53..646b462d04df 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -115,7 +115,6 @@ struct request {
void *elevator_private3;
struct gendisk *rq_disk;
- struct hd_struct *part;
unsigned long start_time;
#ifdef CONFIG_BLK_CGROUP
unsigned long long start_time_ns;
diff --git a/include/linux/coda_fs_i.h b/include/linux/coda_fs_i.h
index b3ef0c461578..e35071b1de0e 100644
--- a/include/linux/coda_fs_i.h
+++ b/include/linux/coda_fs_i.h
@@ -10,19 +10,24 @@
#include <linux/types.h>
#include <linux/list.h>
+#include <linux/spinlock.h>
#include <linux/coda.h>
/*
* coda fs inode data
+ * c_lock protects accesses to c_flags, c_mapcount, c_cached_epoch, c_uid and
+ * c_cached_perm.
+ * vfs_inode is set only when the inode is created and never changes.
+ * c_fid is set when the inode is created and should be considered immutable.
*/
struct coda_inode_info {
- struct CodaFid c_fid; /* Coda identifier */
- u_short c_flags; /* flags (see below) */
- struct list_head c_cilist; /* list of all coda inodes */
+ struct CodaFid c_fid; /* Coda identifier */
+ u_short c_flags; /* flags (see below) */
unsigned int c_mapcount; /* nr of times this inode is mapped */
unsigned int c_cached_epoch; /* epoch for cached permissions */
vuid_t c_uid; /* fsuid for cached permissions */
- unsigned int c_cached_perm; /* cached access permissions */
+ unsigned int c_cached_perm; /* cached access permissions */
+ spinlock_t c_lock;
struct inode vfs_inode;
};
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index dcc228aa335a..2e914d0771b9 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -89,7 +89,11 @@ static __inline__ char *coda_i2s(struct inode *inode)
/* this will not zap the inode away */
static __inline__ void coda_flag_inode(struct inode *inode, int flag)
{
- ITOC(inode)->c_flags |= flag;
+ struct coda_inode_info *cii = ITOC(inode);
+
+ spin_lock(&cii->c_lock);
+ cii->c_flags |= flag;
+ spin_unlock(&cii->c_lock);
}
#endif
diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
index 284b520934a0..72f2d2f0af91 100644
--- a/include/linux/coda_psdev.h
+++ b/include/linux/coda_psdev.h
@@ -8,6 +8,7 @@
#ifdef __KERNEL__
#include <linux/backing-dev.h>
+#include <linux/mutex.h>
struct kstatfs;
@@ -20,6 +21,7 @@ struct venus_comm {
int vc_inuse;
struct super_block *vc_sb;
struct backing_dev_info bdi;
+ struct mutex vc_mutex;
};
@@ -63,7 +65,7 @@ int venus_symlink(struct super_block *sb, struct CodaFid *fid,
int venus_access(struct super_block *sb, struct CodaFid *fid, int mask);
int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
unsigned int cmd, struct PioctlData *data);
-int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb);
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out);
int venus_fsync(struct super_block *sb, struct CodaFid *fid);
int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 80a0ece8f7e4..4fd978e7eb83 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -122,8 +122,6 @@ extern void elv_completed_request(struct request_queue *, struct request *);
extern int elv_set_request(struct request_queue *, struct request *, gfp_t);
extern void elv_put_request(struct request_queue *, struct request *);
extern void elv_drain_elevator(struct request_queue *);
-extern void elv_quiesce_start(struct request_queue *);
-extern void elv_quiesce_end(struct request_queue *);
/*
* io scheduler registration
diff --git a/include/linux/gameport.h b/include/linux/gameport.h
index 361d1cc288d0..b65a6f472775 100644
--- a/include/linux/gameport.h
+++ b/include/linux/gameport.h
@@ -53,9 +53,7 @@ struct gameport {
#define to_gameport_port(d) container_of(d, struct gameport, dev)
struct gameport_driver {
-
- void *private;
- char *description;
+ const char *description;
int (*connect)(struct gameport *, struct gameport_driver *drv);
int (*reconnect)(struct gameport *);
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 557c3927e70f..7a7b9c1644e4 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -140,7 +140,6 @@ struct disk_part_tbl {
struct rcu_head rcu_head;
int len;
struct hd_struct __rcu *last_lookup;
- struct gendisk *disk;
struct hd_struct __rcu *part[];
};
diff --git a/include/linux/input.h b/include/linux/input.h
index d6ae1761be97..51af441f3a21 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -34,7 +34,7 @@ struct input_event {
* Protocol version.
*/
-#define EV_VERSION 0x010000
+#define EV_VERSION 0x010001
/*
* IOCTLs (0x00 - 0x7f)
@@ -56,25 +56,50 @@ struct input_absinfo {
__s32 resolution;
};
+/**
+ * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
+ * @scancode: scancode represented in machine-endian form.
+ * @len: length of the scancode that resides in @scancode buffer.
+ * @index: index in the keymap, may be used instead of scancode
+ * @flags: allows to specify how kernel should handle the request. For
+ * example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel
+ * should perform lookup in keymap by @index instead of @scancode
+ * @keycode: key code assigned to this scancode
+ *
+ * The structure is used to retrieve and modify keymap data. Users have
+ * option of performing lookup either by @scancode itself or by @index
+ * in keymap entry. EVIOCGKEYCODE will also return scancode or index
+ * (depending on which element was used to perform lookup).
+ */
+struct input_keymap_entry {
+#define INPUT_KEYMAP_BY_INDEX (1 << 0)
+ __u8 flags;
+ __u8 len;
+ __u16 index;
+ __u32 keycode;
+ __u8 scancode[32];
+};
+
#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */
#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */
-#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */
-#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */
+
+#define EVIOCGKEYCODE _IOR('E', 0x04, struct input_keymap_entry) /* get keycode */
+#define EVIOCSKEYCODE _IOW('E', 0x04, struct input_keymap_entry) /* set keycode */
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
-#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
+#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
-#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
-#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
+#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
+#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
@@ -1088,13 +1113,13 @@ struct input_mt_slot {
* @keycodemax: size of keycode table
* @keycodesize: size of elements in keycode table
* @keycode: map of scancodes to keycodes for this device
+ * @getkeycode: optional legacy method to retrieve current keymap.
* @setkeycode: optional method to alter current keymap, used to implement
* sparse keymaps. If not supplied default mechanism will be used.
* The method is being called while holding event_lock and thus must
* not sleep
- * @getkeycode: optional method to retrieve current keymap. If not supplied
- * default mechanism will be used. The method is being called while
- * holding event_lock and thus must not sleep
+ * @getkeycode_new: transition method
+ * @setkeycode_new: transition method
* @ff: force feedback structure associated with the device if device
* supports force feedback effects
* @repeat_key: stores key code of the last key pressed; used to implement
@@ -1168,10 +1193,16 @@ struct input_dev {
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
+
int (*setkeycode)(struct input_dev *dev,
unsigned int scancode, unsigned int keycode);
int (*getkeycode)(struct input_dev *dev,
unsigned int scancode, unsigned int *keycode);
+ int (*setkeycode_new)(struct input_dev *dev,
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode);
+ int (*getkeycode_new)(struct input_dev *dev,
+ struct input_keymap_entry *ke);
struct ff_device *ff;
@@ -1478,10 +1509,12 @@ INPUT_GENERATE_ABS_ACCESSORS(fuzz, fuzz)
INPUT_GENERATE_ABS_ACCESSORS(flat, flat)
INPUT_GENERATE_ABS_ACCESSORS(res, resolution)
-int input_get_keycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode);
+int input_scancode_to_scalar(const struct input_keymap_entry *ke,
+ unsigned int *scancode);
+
+int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke);
int input_set_keycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode);
+ const struct input_keymap_entry *ke);
extern struct class input_class;
diff --git a/include/linux/input/bu21013.h b/include/linux/input/bu21013.h
new file mode 100644
index 000000000000..e470d387dd49
--- /dev/null
+++ b/include/linux/input/bu21013.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * License terms:GNU General Public License (GPL) version 2
+ */
+
+#ifndef _BU21013_H
+#define _BU21013_H
+
+/**
+ * struct bu21013_platform_device - Handle the platform data
+ * @cs_en: pointer to the cs enable function
+ * @cs_dis: pointer to the cs disable function
+ * @irq_read_val: pointer to read the pen irq value function
+ * @x_max_res: xmax resolution
+ * @y_max_res: ymax resolution
+ * @touch_x_max: touch x max
+ * @touch_y_max: touch y max
+ * @cs_pin: chip select pin
+ * @irq: irq pin
+ * @ext_clk: external clock flag
+ * @x_flip: x flip flag
+ * @y_flip: y flip flag
+ * @wakeup: wakeup flag
+ *
+ * This is used to handle the platform data
+ */
+struct bu21013_platform_device {
+ int (*cs_en)(int reset_pin);
+ int (*cs_dis)(int reset_pin);
+ int (*irq_read_val)(void);
+ int x_max_res;
+ int y_max_res;
+ int touch_x_max;
+ int touch_y_max;
+ unsigned int cs_pin;
+ unsigned int irq;
+ bool ext_clk;
+ bool x_flip;
+ bool y_flip;
+ bool wakeup;
+};
+
+#endif
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index 835f85ecd2de..975d347079d9 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -27,20 +27,19 @@ static inline int of_driver_match_device(const struct device *dev,
extern struct platform_device *of_dev_get(struct platform_device *dev);
extern void of_dev_put(struct platform_device *dev);
+extern int of_device_add(struct platform_device *pdev);
extern int of_device_register(struct platform_device *ofdev);
extern void of_device_unregister(struct platform_device *ofdev);
-extern void of_release_dev(struct device *dev);
-
-static inline void of_device_free(struct platform_device *dev)
-{
- of_release_dev(&dev->dev);
-}
extern ssize_t of_device_get_modalias(struct device *dev,
char *str, ssize_t len);
extern int of_device_uevent(struct device *dev, struct kobj_uevent_env *env);
+static inline void of_device_node_put(struct device *dev)
+{
+ of_node_put(dev->of_node);
+}
#else /* CONFIG_OF_DEVICE */
@@ -56,6 +55,8 @@ static inline int of_device_uevent(struct device *dev,
return -ENODEV;
}
+static inline void of_device_node_put(struct device *dev) { }
+
#endif /* CONFIG_OF_DEVICE */
#endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 71e1a916d3fa..7bbf5b328438 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -72,7 +72,7 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
unsigned long *size);
extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
extern unsigned long of_get_flat_dt_root(void);
-extern void early_init_dt_scan_chosen_arch(unsigned long node);
+
extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data);
extern void early_init_dt_check_for_initrd(unsigned long node);
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index 5929781c104d..109e013b1772 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -5,6 +5,7 @@
struct of_irq;
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/irq.h>
#include <linux/ioport.h>
#include <linux/of.h>
@@ -64,6 +65,9 @@ extern unsigned int irq_create_of_mapping(struct device_node *controller,
unsigned int intsize);
extern int of_irq_to_resource(struct device_node *dev, int index,
struct resource *r);
+extern int of_irq_count(struct device_node *dev);
+extern int of_irq_to_resource_table(struct device_node *dev,
+ struct resource *res, int nr_irqs);
#endif /* CONFIG_OF_IRQ */
#endif /* CONFIG_OF */
diff --git a/include/linux/of_pdt.h b/include/linux/of_pdt.h
new file mode 100644
index 000000000000..c65a18a0cfdf
--- /dev/null
+++ b/include/linux/of_pdt.h
@@ -0,0 +1,45 @@
+/*
+ * Definitions for building a device tree by calling into the
+ * Open Firmware PROM.
+ *
+ * Copyright (C) 2010 Andres Salomon <dilinger@queued.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_OF_PDT_H
+#define _LINUX_OF_PDT_H
+
+/* overridable operations for calling into the PROM */
+struct of_pdt_ops {
+ /*
+ * buf should be 32 bytes; return 0 on success.
+ * If prev is NULL, the first property will be returned.
+ */
+ int (*nextprop)(phandle node, char *prev, char *buf);
+
+ /* for both functions, return proplen on success; -1 on error */
+ int (*getproplen)(phandle node, const char *prop);
+ int (*getproperty)(phandle node, const char *prop, char *buf,
+ int bufsize);
+
+ /* phandles are 0 if no child or sibling exists */
+ phandle (*getchild)(phandle parent);
+ phandle (*getsibling)(phandle node);
+
+ /* return 0 on success; fill in 'len' with number of bytes in path */
+ int (*pkg2path)(phandle node, char *buf, const int buflen, int *len);
+};
+
+extern void *prom_early_alloc(unsigned long size);
+
+/* for building the device tree */
+extern void of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops);
+
+extern void (*of_pdt_build_more)(struct device_node *dp,
+ struct device_node ***nextp);
+
+#endif /* _LINUX_OF_PDT_H */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index d278dd9cb765..b4c3d1b50037 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2268,6 +2268,13 @@
#define PCI_VENDOR_ID_SILAN 0x1904
+#define PCI_VENDOR_ID_RENESAS 0x1912
+#define PCI_DEVICE_ID_RENESAS_SH7781 0x0001
+#define PCI_DEVICE_ID_RENESAS_SH7780 0x0002
+#define PCI_DEVICE_ID_RENESAS_SH7763 0x0004
+#define PCI_DEVICE_ID_RENESAS_SH7785 0x0007
+#define PCI_DEVICE_ID_RENESAS_SH7786 0x0010
+
#define PCI_VENDOR_ID_TDI 0x192E
#define PCI_DEVICE_ID_TDI_EHCI 0x0101
diff --git a/include/linux/serio.h b/include/linux/serio.h
index b5552568178d..e26f4788845f 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -41,7 +41,9 @@ struct serio {
int (*start)(struct serio *);
void (*stop)(struct serio *);
- struct serio *parent, *child;
+ struct serio *parent;
+ struct list_head child_node; /* Entry in parent->children list */
+ struct list_head children;
unsigned int depth; /* level of nesting in serio hierarchy */
struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */
@@ -54,10 +56,9 @@ struct serio {
#define to_serio_port(d) container_of(d, struct serio, dev)
struct serio_driver {
- void *private;
- char *description;
+ const char *description;
- struct serio_device_id *id_table;
+ const struct serio_device_id *id_table;
bool manual_bind;
void (*write_wakeup)(struct serio *);
@@ -197,5 +198,6 @@ static inline void serio_continue_rx(struct serio *serio)
#define SERIO_W8001 0x39
#define SERIO_DYNAPRO 0x3a
#define SERIO_HAMPSHIRE 0x3b
+#define SERIO_PS2MULT 0x3c
#endif
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index 875ce50719a9..4dca992f3093 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -4,11 +4,20 @@
#include <linux/list.h>
#include <linux/seq_file.h>
#include <linux/cpufreq.h>
+#include <linux/types.h>
+#include <linux/kref.h>
#include <linux/clk.h>
#include <linux/err.h>
struct clk;
+struct clk_mapping {
+ phys_addr_t phys;
+ void __iomem *base;
+ unsigned long len;
+ struct kref ref;
+};
+
struct clk_ops {
void (*init)(struct clk *clk);
int (*enable)(struct clk *clk);
@@ -21,9 +30,6 @@ struct clk_ops {
struct clk {
struct list_head node;
- const char *name;
- int id;
-
struct clk *parent;
struct clk **parent_table; /* list of parents to */
unsigned short parent_num; /* choose between */
@@ -45,7 +51,9 @@ struct clk {
unsigned long arch_flags;
void *priv;
struct dentry *dentry;
+ struct clk_mapping *mapping;
struct cpufreq_frequency_table *freq_table;
+ unsigned int nr_freqs;
};
#define CLK_ENABLE_ON_INIT (1 << 0)
@@ -111,6 +119,9 @@ int clk_rate_table_find(struct clk *clk,
struct cpufreq_frequency_table *freq_table,
unsigned long rate);
+long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
+ unsigned int div_max, unsigned long rate);
+
#define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags) \
{ \
.parent = _parent, \
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index 0d6cd38e673d..b4f183a31f13 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -20,6 +20,12 @@ struct intc_group {
#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } }
+struct intc_subgroup {
+ unsigned long reg, reg_width;
+ intc_enum parent_id;
+ intc_enum enum_ids[32];
+};
+
struct intc_mask_reg {
unsigned long set_reg, clr_reg, reg_width;
intc_enum enum_ids[32];
@@ -69,9 +75,12 @@ struct intc_hw_desc {
unsigned int nr_sense_regs;
struct intc_mask_reg *ack_regs;
unsigned int nr_ack_regs;
+ struct intc_subgroup *subgroups;
+ unsigned int nr_subgroups;
};
-#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
+#define _INTC_ARRAY(a) a, a == NULL ? 0 : sizeof(a)/sizeof(*a)
+
#define INTC_HW_DESC(vectors, groups, mask_regs, \
prio_regs, sense_regs, ack_regs) \
{ \
@@ -105,8 +114,11 @@ struct intc_desc symbol __initdata = { \
prio_regs, sense_regs, ack_regs), \
}
-int __init register_intc_controller(struct intc_desc *desc);
+int register_intc_controller(struct intc_desc *desc);
+void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
int intc_set_priority(unsigned int irq, unsigned int prio);
+int intc_irq_lookup(const char *chipname, intc_enum enum_id);
+void intc_finalize(void);
#ifdef CONFIG_INTC_USERIMASK
int register_intc_userimask(unsigned long addr);
diff --git a/include/linux/sh_pfc.h b/include/linux/sh_pfc.h
index 07c08af9f8f6..30cae70874f4 100644
--- a/include/linux/sh_pfc.h
+++ b/include/linux/sh_pfc.h
@@ -92,5 +92,6 @@ struct pinmux_info {
};
int register_pinmux(struct pinmux_info *pip);
+int unregister_pinmux(struct pinmux_info *pip);
#endif /* __SH_PFC_H */
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index a9c041d49662..9b201ec8dc7f 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -35,7 +35,7 @@ struct ir_scancode_table {
unsigned int len; /* Used number of entries */
unsigned int alloc; /* Size of *scan in bytes */
u64 ir_type;
- char *name;
+ const char *name;
spinlock_t lock;
};
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index 36170be15aa7..b0ccd0b862fc 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -127,6 +127,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info,
sg_init_table(&sg, 1);
sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
size, offset_in_page(buff));
+ sg_dma_len(&sg) = size;
sg_dma_address(&sg) = buff;
desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
@@ -176,6 +177,7 @@ static int siu_pcm_rd_set(struct siu_port *port_info,
sg_init_table(&sg, 1);
sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
size, offset_in_page(buff));
+ sg_dma_len(&sg) = size;
sg_dma_address(&sg) = buff;
desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,