]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'msm-smp' of git://codeaurora.org/quic/kernel/davidb/linux-msm
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Jan 2011 22:50:08 +0000 (14:50 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Jan 2011 22:50:08 +0000 (14:50 -0800)
* 'msm-smp' of git://codeaurora.org/quic/kernel/davidb/linux-msm:
  msm: add SMP support for msm
  msm: hotplug: support cpu hotplug on msm
  msm: timer: SMP timer support for msm
  msm: scm-boot: Support for setting cold/warm boot addresses
  msm: Secure Channel Manager (SCM) support

564 files changed:
Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus [new file with mode: 0644]
Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
Documentation/coccinelle.txt
Documentation/feature-removal-schedule.txt
Documentation/hwmon/ds620 [new file with mode: 0644]
Documentation/hwmon/sht21 [new file with mode: 0644]
Documentation/hwmon/sysfs-interface
Documentation/kbuild/kbuild.txt
Documentation/kbuild/kconfig-language.txt
Documentation/kbuild/makefiles.txt
Documentation/keys-trusted-encrypted.txt [new file with mode: 0644]
Documentation/make/headers_install.txt
Documentation/power/drivers-testing.txt
Documentation/power/runtime_pm.txt
Documentation/powerpc/dts-bindings/eeprom.txt [new file with mode: 0644]
Documentation/spi/pxa2xx
Documentation/sysctl/kernel.txt
Documentation/vm/Makefile
MAINTAINERS
Makefile
arch/arm/mach-davinci/dm355.c
arch/arm/mach-davinci/dm365.c
arch/arm/mach-davinci/include/mach/spi.h
arch/arm/mach-pxa/cm-x255.c
arch/arm/mach-pxa/cm-x270.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-pxa/icontrol.c
arch/arm/mach-pxa/include/mach/pxa2xx_spi.h [deleted file]
arch/arm/mach-pxa/littleton.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/pcm027.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/sharpsl_pm.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/stargate2.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-pxa/trizeps4.c
arch/arm/mach-pxa/z2.c
arch/arm/mach-pxa/zeus.c
arch/arm/plat-pxa/ssp.c
arch/arm/plat-s3c24xx/cpu-freq.c
arch/microblaze/Kconfig
arch/microblaze/boot/Makefile
arch/microblaze/include/asm/prom.h
arch/microblaze/kernel/prom_parse.c
arch/mips/Kconfig
arch/powerpc/Kconfig
arch/powerpc/boot/Makefile
arch/powerpc/boot/dts/bluestone.dts
arch/powerpc/boot/dts/cm5200.dts
arch/powerpc/boot/dts/digsy_mtc.dts
arch/powerpc/boot/dts/hotfoot.dts
arch/powerpc/boot/dts/lite5200b.dts
arch/powerpc/boot/dts/media5200.dts
arch/powerpc/boot/dts/motionpro.dts
arch/powerpc/boot/dts/mpc5200b.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/mucmc52.dts
arch/powerpc/boot/dts/pcm030.dts
arch/powerpc/boot/dts/pcm032.dts
arch/powerpc/boot/dts/uc101.dts
arch/powerpc/include/asm/prom.h
arch/powerpc/kernel/prom_parse.c
arch/powerpc/platforms/40x/ppc40x_simple.c
arch/powerpc/platforms/512x/mpc5121_generic.c
arch/powerpc/platforms/52xx/lite5200.c
arch/powerpc/platforms/52xx/media5200.c
arch/powerpc/platforms/52xx/mpc5200_simple.c
arch/powerpc/platforms/83xx/mpc830x_rdb.c
arch/powerpc/platforms/83xx/mpc831x_rdb.c
arch/powerpc/platforms/83xx/mpc837x_rdb.c
arch/powerpc/platforms/85xx/tqm85xx.c
arch/powerpc/platforms/pseries/eeh_sysfs.c
arch/powerpc/sysdev/mv64x60_dev.c
arch/powerpc/sysdev/tsi108_dev.c
arch/sh/drivers/push-switch.c
arch/sparc/kernel/auxio_32.c
arch/sparc/kernel/starfire.c
arch/sparc/prom/init_32.c
arch/sparc/prom/init_64.c
arch/sparc/prom/tree_32.c
arch/sparc/prom/tree_64.c
arch/x86/Kconfig.cpu
arch/x86/include/asm/debugreg.h
arch/x86/include/asm/hypervisor.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/mce_intel.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/ftrace.c
arch/x86/kernel/hw_breakpoint.c
arch/x86/kernel/irq.c
arch/x86/kernel/irq_32.c
arch/x86/kernel/kprobes.c
arch/x86/kernel/process.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/tsc.c
arch/x86/kvm/x86.c
arch/x86/lib/delay.c
arch/x86/oprofile/nmi_int.c
arch/x86/oprofile/op_model_ppro.c
arch/x86/xen/enlighten.c
arch/x86/xen/multicalls.h
arch/x86/xen/spinlock.c
arch/x86/xen/time.c
drivers/acpi/processor_idle.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/acard-ahci.c [new file with mode: 0644]
drivers/ata/ahci.h
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/base/core.c
drivers/base/power/generic_ops.c
drivers/base/power/main.c
drivers/base/power/runtime.c
drivers/base/power/wakeup.c
drivers/block/floppy.c
drivers/block/xen-blkfront.c
drivers/cdrom/gdrom.c
drivers/char/hvsi.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/pcmcia/ipwireless/hardware.c
drivers/char/pcmcia/ipwireless/network.c
drivers/char/pcmcia/ipwireless/tty.c
drivers/char/random.c
drivers/char/snsc.h
drivers/char/sonypi.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/connector/cn_proc.c
drivers/cpuidle/cpuidle.c
drivers/firewire/Kconfig
drivers/firewire/core-cdev.c
drivers/firewire/core-transaction.c
drivers/firewire/core.h
drivers/firewire/net.c
drivers/firewire/nosy.c
drivers/firewire/ohci.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-3m-pct.c
drivers/hid/hid-a4tech.c
drivers/hid/hid-apple.c
drivers/hid/hid-axff.c
drivers/hid/hid-belkin.c
drivers/hid/hid-cando.c
drivers/hid/hid-cherry.c
drivers/hid/hid-core.c
drivers/hid/hid-cypress.c
drivers/hid/hid-debug.c
drivers/hid/hid-drff.c
drivers/hid/hid-egalax.c
drivers/hid/hid-elecom.c
drivers/hid/hid-emsff.c [new file with mode: 0644]
drivers/hid/hid-gaff.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-kye.c
drivers/hid/hid-lg.c
drivers/hid/hid-lg2ff.c
drivers/hid/hid-lg3ff.c
drivers/hid/hid-lg4ff.c
drivers/hid/hid-lgff.c
drivers/hid/hid-magicmouse.c
drivers/hid/hid-microsoft.c
drivers/hid/hid-monterey.c
drivers/hid/hid-mosart.c
drivers/hid/hid-ntrig.c
drivers/hid/hid-ortek.c
drivers/hid/hid-petalynx.c
drivers/hid/hid-picolcd.c
drivers/hid/hid-pl.c
drivers/hid/hid-prodikeys.c
drivers/hid/hid-quanta.c
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-roccat-kone.h
drivers/hid/hid-roccat-koneplus.c [new file with mode: 0644]
drivers/hid/hid-roccat-koneplus.h [new file with mode: 0644]
drivers/hid/hid-roccat-pyra.c
drivers/hid/hid-roccat-pyra.h
drivers/hid/hid-roccat.c
drivers/hid/hid-roccat.h
drivers/hid/hid-samsung.c
drivers/hid/hid-sjoy.c
drivers/hid/hid-sony.c
drivers/hid/hid-stantum.c
drivers/hid/hid-sunplus.c
drivers/hid/hid-tmff.c
drivers/hid/hid-topseed.c
drivers/hid/hid-wacom.c
drivers/hid/hid-zpff.c
drivers/hid/hid-zydacron.c
drivers/hid/hidraw.c
drivers/hid/usbhid/Makefile
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-pidff.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hiddev.c
drivers/hid/usbhid/usbhid.h
drivers/hid/usbhid/usbkbd.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru.c
drivers/hwmon/abituguru3.c
drivers/hwmon/adt7470.c
drivers/hwmon/applesmc.c
drivers/hwmon/asb100.c
drivers/hwmon/asus_atk0110.c
drivers/hwmon/coretemp.c
drivers/hwmon/dme1737.c
drivers/hwmon/ds620.c [new file with mode: 0644]
drivers/hwmon/f71805f.c
drivers/hwmon/f71882fg.c
drivers/hwmon/hp_accel.c
drivers/hwmon/hwmon-vid.c
drivers/hwmon/hwmon.c
drivers/hwmon/ibmaem.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lm70.c
drivers/hwmon/lm95241.c
drivers/hwmon/pcf8591.c
drivers/hwmon/pkgtemp.c
drivers/hwmon/sht21.c [new file with mode: 0644]
drivers/hwmon/sis5595.c
drivers/hwmon/smsc47b397.c
drivers/hwmon/smsc47m1.c
drivers/hwmon/via-cputemp.c
drivers/hwmon/via686a.c
drivers/hwmon/vt1211.c
drivers/hwmon/vt8231.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83627hf.c
drivers/input/gameport/gameport.c
drivers/input/mouse/bcm5974.c
drivers/isdn/capi/capidrv.c
drivers/isdn/capi/kcapi.c
drivers/isdn/mISDN/hwchannel.c
drivers/isdn/mISDN/l1oip_core.c
drivers/leds/leds-wm8350.c
drivers/macintosh/ams/ams-core.c
drivers/macintosh/rack-meter.c
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
drivers/media/dvb/mantis/mantis_evm.c
drivers/media/dvb/mantis/mantis_uart.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx23885/cx23885-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/omap24xxcam.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/mfd/menelaus.c
drivers/mfd/tps65010.c
drivers/misc/eeprom/at24.c
drivers/misc/ioc4.c
drivers/mmc/core/core.c
drivers/mmc/host/Kconfig
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-of-core.c
drivers/mtd/Kconfig
drivers/mtd/maps/Kconfig
drivers/net/bonding/bonding.h
drivers/net/chelsio/my3126.c
drivers/net/fs_enet/fs_enet-main.c
drivers/net/gianfar.c
drivers/net/ibm_newemac/core.c
drivers/net/ucc_geth.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/net/xilinx_emaclite.c
drivers/of/Kconfig
drivers/of/Makefile
drivers/of/address.c
drivers/of/fdt.c
drivers/of/of_mdio.c
drivers/of/of_net.c [new file with mode: 0644]
drivers/of/platform.c
drivers/pci/hotplug/acpiphp.h
drivers/pci/hotplug/rpaphp_slot.c
drivers/power/ds2760_battery.c
drivers/power/intel_mid_battery.c
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-ds3232.c
drivers/rtc/rtc-rx8025.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tape_block.c
drivers/s390/char/tape_class.h
drivers/s390/cio/cio.c
drivers/sbus/char/jsflash.c
drivers/scsi/ipr.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/serial/Kconfig
drivers/serial/of_serial.c
drivers/sh/clk/core.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/amba-pl022.c
drivers/spi/davinci_spi.c
drivers/spi/dw_spi.c
drivers/spi/dw_spi_mid.c [new file with mode: 0644]
drivers/spi/dw_spi_pci.c
drivers/spi/mpc52xx_psc_spi.c
drivers/spi/omap2_mcspi.c
drivers/spi/pxa2xx_spi.c
drivers/spi/pxa2xx_spi_pci.c [new file with mode: 0644]
drivers/spi/spi.c
drivers/spi/spi_imx.c
drivers/spi/spi_nuc900.c
drivers/spi/spi_topcliff_pch.c
drivers/spi/xilinx_spi.c
drivers/spi/xilinx_spi.h [deleted file]
drivers/spi/xilinx_spi_of.c [deleted file]
drivers/spi/xilinx_spi_pltfm.c [deleted file]
drivers/staging/lirc/lirc_serial.c
drivers/staging/pohmelfs/inode.c
drivers/staging/speakup/fakekey.c
drivers/usb/atm/cxacru.c
drivers/usb/atm/speedtch.c
drivers/usb/core/driver.c
drivers/usb/gadget/u_ether.c
drivers/usb/host/ohci-hcd.c
drivers/usb/musb/musb_debugfs.c
drivers/usb/otg/isp1301_omap.c
drivers/usb/serial/oti6858.c
drivers/video/fb_defio.c
drivers/video/omap/lcd_mipid.c
drivers/video/xen-fbfront.c
drivers/xen/events.c
fs/buffer.c
fs/cifs/cache.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_spnego.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/transport.c
fs/dlm/lowcomms.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/incore.h
fs/hfsplus/bfind.c
fs/hfsplus/bitmap.c
fs/hfsplus/bnode.c
fs/hfsplus/brec.c
fs/hfsplus/btree.c
fs/hfsplus/catalog.c
fs/hfsplus/dir.c
fs/hfsplus/extents.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/hfsplus_raw.h
fs/hfsplus/inode.c
fs/hfsplus/ioctl.c
fs/hfsplus/options.c
fs/hfsplus/part_tbl.c
fs/hfsplus/super.c
fs/hfsplus/unicode.c
fs/hfsplus/wrapper.c
fs/namei.c
fs/ncpfs/inode.c
fs/nfsd/nfs4state.c
fs/nilfs2/bmap.c
fs/nilfs2/btnode.c
fs/nilfs2/dir.c
fs/nilfs2/file.c
fs/nilfs2/ifile.c
fs/nilfs2/inode.c
fs/nilfs2/ioctl.c
fs/nilfs2/mdt.c
fs/nilfs2/namei.c
fs/nilfs2/nilfs.h
fs/nilfs2/page.c
fs/nilfs2/page.h
fs/nilfs2/recovery.c
fs/nilfs2/sb.h
fs/nilfs2/segment.c
fs/nilfs2/super.c
fs/nilfs2/the_nilfs.c
fs/nilfs2/the_nilfs.h
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/quorum.c
fs/sysfs/inode.c
fs/sysfs/sysfs.h
fs/xfs/xfs_mru_cache.c
include/asm-generic/irq_regs.h
include/asm-generic/vmlinux.lds.h
include/keys/encrypted-type.h [new file with mode: 0644]
include/keys/trusted-type.h [new file with mode: 0644]
include/linux/Kbuild
include/linux/audit.h
include/linux/capability.h
include/linux/dcache.h
include/linux/dcookies.h
include/linux/device.h
include/linux/elevator.h
include/linux/firewire.h
include/linux/firmware-map.h
include/linux/flex_array.h
include/linux/fs.h
include/linux/fuse.h
include/linux/hid.h
include/linux/highmem.h
include/linux/hrtimer.h
include/linux/i2c/ds620.h [new file with mode: 0644]
include/linux/kernel.h
include/linux/kernel_stat.h
include/linux/kprobes.h
include/linux/libata.h
include/linux/of_address.h
include/linux/of_fdt.h
include/linux/of_net.h [new file with mode: 0644]
include/linux/percpu.h
include/linux/pipe_fs_i.h
include/linux/pm.h
include/linux/pm_runtime.h
include/linux/pxa2xx_ssp.h [moved from arch/arm/plat-pxa/include/plat/ssp.h with 90% similarity]
include/linux/sched.h
include/linux/security.h
include/linux/slab_def.h
include/linux/slub_def.h
include/linux/spi/dw_spi.h
include/linux/spi/pxa2xx_spi.h [new file with mode: 0644]
include/linux/sunrpc/cache.h
include/linux/suspend.h
include/linux/tpm.h
include/linux/tpm_command.h [new file with mode: 0644]
include/linux/workqueue.h
include/linux/xattr.h
init/main.c
kernel/Makefile
kernel/exit.c
kernel/fork.c
kernel/freezer.c
kernel/hrtimer.c
kernel/irq_work.c
kernel/kprobes.c
kernel/power/Makefile
kernel/power/hibernate.c
kernel/power/process.c
kernel/power/suspend.c
kernel/printk.c
kernel/rcutree.c
kernel/softirq.c
kernel/taskstats.c
kernel/time/tick-common.c
kernel/time/tick-oneshot.c
kernel/watchdog.c
kernel/workqueue.c
lib/hexdump.c
lib/percpu_counter.c
mm/percpu.c
mm/slab.c
mm/slub.c
mm/vmstat.c
net/atm/lec.c
net/core/netpoll.c
net/dsa/dsa.c
net/netfilter/ipvs/ip_vs_ctl.c
net/sunrpc/xprtsock.c
scripts/.gitignore
scripts/Makefile.lib
scripts/basic/fixdep.c
scripts/checksyscalls.sh
scripts/coccinelle/misc/doubleinit.cocci
scripts/coccinelle/null/deref_null.cocci
scripts/config
scripts/dtc/Makefile
scripts/dtc/checks.c
scripts/dtc/dtc-lexer.l
scripts/dtc/dtc-lexer.lex.c_shipped
scripts/dtc/dtc-parser.tab.c_shipped
scripts/dtc/dtc-parser.tab.h_shipped
scripts/dtc/dtc-parser.y
scripts/dtc/dtc.c
scripts/dtc/dtc.h
scripts/dtc/flattree.c
scripts/dtc/fstree.c
scripts/dtc/livetree.c
scripts/dtc/srcpos.c
scripts/dtc/srcpos.h
scripts/dtc/treesource.c
scripts/dtc/util.c [new file with mode: 0644]
scripts/dtc/util.h [new file with mode: 0644]
scripts/dtc/version_gen.h
scripts/genksyms/parse.c_shipped
scripts/genksyms/parse.y
scripts/headers.sh
scripts/headers_check.pl
scripts/headers_install.pl
scripts/kconfig/conf.c
scripts/kconfig/confdata.c
scripts/kconfig/expr.c
scripts/kconfig/expr.h
scripts/kconfig/lkc.h
scripts/kconfig/menu.c
scripts/kconfig/nconf.c
scripts/kconfig/symbol.c
scripts/mkuboot.sh
scripts/mod/modpost.c
scripts/package/builddeb
scripts/tags.sh
security/Kconfig
security/apparmor/include/file.h
security/apparmor/include/match.h
security/keys/Makefile
security/keys/encrypted_defined.c [new file with mode: 0644]
security/keys/encrypted_defined.h [new file with mode: 0644]
security/keys/trusted_defined.c [new file with mode: 0644]
security/keys/trusted_defined.h [new file with mode: 0644]
security/selinux/hooks.c
security/selinux/include/avc.h
security/selinux/include/classmap.h
security/selinux/nlmsgtab.c
security/selinux/selinuxfs.c
security/selinux/ss/conditional.c
security/selinux/ss/mls.c
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c
security/selinux/ss/sidtab.c
security/selinux/ss/sidtab.h
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c
sound/soc/pxa/pxa-ssp.c
tools/slub/slabinfo.c [moved from Documentation/vm/slabinfo.c with 99% similarity]
usr/gen_init_cpio.c

index 063bda7fe7079ad538e5a54f3fcec1930d3ff56c..698b8081c473330cbf48fbd5568a64b6383ae568 100644 (file)
@@ -1,4 +1,4 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_dpi
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/actual_dpi
 Date:          March 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   It is possible to switch the dpi setting of the mouse with the
@@ -17,13 +17,13 @@ Description:        It is possible to switch the dpi setting of the mouse with the
 
                This file is readonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_profile
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/actual_profile
 Date:          March 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   When read, this file returns the number of the actual profile.
                This file is readonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/firmware_version
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/firmware_version
 Date:          March 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   When read, this file returns the raw integer version number of the
@@ -33,7 +33,7 @@ Description:  When read, this file returns the raw integer version number of the
                left. E.g. a returned value of 138 means 1.38
                This file is readonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/profile[1-5]
 Date:          March 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   The mouse can store 5 profiles which can be switched by the
@@ -48,7 +48,7 @@ Description:  The mouse can store 5 profiles which can be switched by the
                stored in the profile doesn't need to fit the number of the
                store.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/settings
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/settings
 Date:          March 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   When read, this file returns the settings stored in the mouse.
@@ -58,7 +58,7 @@ Description:  When read, this file returns the settings stored in the mouse.
                The data has to be 36 bytes long. The mouse will reject invalid
                data.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/startup_profile
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/startup_profile
 Date:          March 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   The integer value of this attribute ranges from 1 to 5.
@@ -67,7 +67,7 @@ Description:  The integer value of this attribute ranges from 1 to 5.
                When written, this file sets the number of the startup profile
                and the mouse activates this profile immediately.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/tcu
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/tcu
 Date:          March 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   The mouse has a "Tracking Control Unit" which lets the user
@@ -78,7 +78,7 @@ Description:  The mouse has a "Tracking Control Unit" which lets the user
                Writing 1 in this file will start the calibration which takes
                around 6 seconds to complete and activates the TCU.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/weight
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/weight
 Date:          March 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   The mouse can be equipped with one of four supplied weights
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
new file mode 100644 (file)
index 0000000..0f9f30e
--- /dev/null
@@ -0,0 +1,108 @@
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/actual_profile
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns the number of the actual profile in
+               range 0-4.
+               This file is readonly.
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/firmware_version
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns the raw integer version number of the
+               firmware reported by the mouse. Using the integer value eases
+               further usage in other programs. To receive the real version
+               number the decimal point has to be shifted 2 positions to the
+               left. E.g. a returned value of 121 means 1.21
+               This file is readonly.
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/macro
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store a macro with max 500 key/button strokes
+               internally.
+               When written, this file lets one set the sequence for a specific
+               button for a specific profile. Button and profile numbers are
+               included in written data. The data has to be 2082 bytes long.
+               This file is writeonly.
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_buttons
+Date:          August 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_buttons holds informations about button layout.
+               When written, this file lets one write the respective profile
+               buttons back to the mouse. The data has to be 77 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               This file is writeonly.
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_buttons
+Date:          August 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_buttons holds informations about button layout.
+               When read, these files return the respective profile buttons.
+               The returned data is 77 bytes in size.
+               This file is readonly.
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_settings
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_settings holds informations like resolution, sensitivity
+               and light effects.
+               When written, this file lets one write the respective profile
+               settings back to the mouse. The data has to be 43 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               This file is writeonly.
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_settings
+Date:          August 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_settings holds informations like resolution, sensitivity
+               and light effects.
+               When read, these files return the respective profile settings.
+               The returned data is 43 bytes in size.
+               This file is readonly.
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/sensor
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse has a tracking- and a distance-control-unit. These
+               can be activated/deactivated and the lift-off distance can be
+               set. The data has to be 6 bytes long.
+               This file is writeonly.
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/startup_profile
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The integer value of this attribute ranges from 0-4.
+                When read, this attribute returns the number of the profile
+                that's active when the mouse is powered on.
+               When written, this file sets the number of the startup profile
+               and the mouse activates this profile immediately.
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written a calibration process for the tracking control unit
+               can be initiated/cancelled.
+               The data has to be 3 bytes long.
+               This file is writeonly.
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu_image
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read the mouse returns a 30x30 pixel image of the
+               sampled underground. This works only in the course of a
+               calibration process initiated with tcu.
+               The returned data is 1028 bytes in size.
+               This file is readonly.
index ad1125b02ff4b809a2bc9b6a2e45fa2a52798868..1c37b823f142229050352cace16a530e7689e329 100644 (file)
@@ -1,4 +1,4 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_cpi
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/actual_cpi
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   It is possible to switch the cpi setting of the mouse with the
@@ -14,14 +14,14 @@ Description:        It is possible to switch the cpi setting of the mouse with the
 
                This file is readonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_profile
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/actual_profile
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   When read, this file returns the number of the actual profile in
                range 0-4.
                This file is readonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/firmware_version
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/firmware_version
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   When read, this file returns the raw integer version number of the
@@ -31,7 +31,7 @@ Description:  When read, this file returns the raw integer version number of the
                left. E.g. a returned value of 138 means 1.38
                This file is readonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_settings
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_settings
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   The mouse can store 5 profiles which can be switched by the
@@ -45,7 +45,7 @@ Description:  The mouse can store 5 profiles which can be switched by the
                contained in the data.
                This file is writeonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_settings
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_settings
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   The mouse can store 5 profiles which can be switched by the
@@ -56,7 +56,7 @@ Description:  The mouse can store 5 profiles which can be switched by the
                The returned data is 13 bytes in size.
                This file is readonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_buttons
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_buttons
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   The mouse can store 5 profiles which can be switched by the
@@ -69,7 +69,7 @@ Description:  The mouse can store 5 profiles which can be switched by the
                contained in the data.
                This file is writeonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_buttons
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_buttons
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   The mouse can store 5 profiles which can be switched by the
@@ -79,7 +79,7 @@ Description:  The mouse can store 5 profiles which can be switched by the
                The returned data is 19 bytes in size.
                This file is readonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/startup_profile
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/startup_profile
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   The integer value of this attribute ranges from 0-4.
@@ -87,7 +87,7 @@ Description:  The integer value of this attribute ranges from 0-4.
                 that's active when the mouse is powered on.
                This file is readonly.
 
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/settings
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/settings
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
 Description:   When read, this file returns the settings stored in the mouse.
index 4a276ea7001c660a8f0dcbe7ff968abcff22a102..96b690348ba14290f10235b94d6e13e4cc2d329d 100644 (file)
@@ -36,6 +36,10 @@ as a regular user, and install it with
 
         sudo make install
 
+The semantic patches in the kernel will work best with Coccinelle version
+0.2.4 or later.  Using earlier versions may incur some parse errors in the
+semantic patch code, but any results that are obtained should still be
+correct.
 
  Using Coccinelle on the Linux kernel
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index f2742e115b09248026093bf405c791227dffa205..22f10818c2b37042b483e6da439590d3c36b80b7 100644 (file)
@@ -566,3 +566,13 @@ Why:       This field is deprecated. I2C device drivers shouldn't change their
 Who:   Jean Delvare <khali@linux-fr.org>
 
 ----------------------------
+
+What:  cancel_rearming_delayed_work[queue]()
+When:  2.6.39
+
+Why:   The functions have been superceded by cancel_delayed_work_sync()
+       quite some time ago.  The conversion is trivial and there is no
+       in-kernel user left.
+Who:   Tejun Heo <tj@kernel.org>
+
+----------------------------
diff --git a/Documentation/hwmon/ds620 b/Documentation/hwmon/ds620
new file mode 100644 (file)
index 0000000..1fbe3cd
--- /dev/null
@@ -0,0 +1,34 @@
+Kernel driver ds620
+===================
+
+Supported chips:
+  * Dallas Semiconductor DS620
+    Prefix: 'ds620'
+    Datasheet: Publicly available at the Dallas Semiconductor website
+               http://www.dalsemi.com/
+
+Authors:
+        Roland Stigge <stigge@antcom.de>
+        based on ds1621.c by
+        Christian W. Zuckschwerdt <zany@triq.net>
+
+Description
+-----------
+
+The DS620 is a (one instance) digital thermometer and thermostat. It has both
+high and low temperature limits which can be user defined (i.e.  programmed
+into non-volatile on-chip registers). Temperature range is -55 degree Celsius
+to +125. Between 0 and 70 degree Celsius, accuracy is 0.5 Kelvin. The value
+returned via sysfs displays post decimal positions.
+
+The thermostat function works as follows: When configured via platform_data
+(struct ds620_platform_data) .pomode == 0 (default), the thermostat output pin
+PO is always low. If .pomode == 1, the thermostat is in PO_LOW mode. I.e., the
+output pin PO becomes active when the temperature falls below temp1_min and
+stays active until the temperature goes above temp1_max.
+
+Likewise, with .pomode == 2, the thermostat is in PO_HIGH mode. I.e., the PO
+output pin becomes active when the temperature goes above temp1_max and stays
+active until the temperature falls below temp1_min.
+
+The PO output pin of the DS620 operates active-low.
diff --git a/Documentation/hwmon/sht21 b/Documentation/hwmon/sht21
new file mode 100644 (file)
index 0000000..db17fda
--- /dev/null
@@ -0,0 +1,49 @@
+Kernel driver sht21
+===================
+
+Supported chips:
+  * Sensirion SHT21
+    Prefix: 'sht21'
+    Addresses scanned: none
+    Datasheet: Publicly available at the Sensirion website
+    http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf
+
+  * Sensirion SHT25
+    Prefix: 'sht21'
+    Addresses scanned: none
+    Datasheet: Publicly available at the Sensirion website
+    http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT25.pdf
+
+Author:
+  Urs Fleisch <urs.fleisch@sensirion.com>
+
+Description
+-----------
+
+The SHT21 and SHT25 are humidity and temperature sensors in a DFN package of
+only 3 x 3 mm footprint and 1.1 mm height. The difference between the two
+devices is the higher level of precision of the SHT25 (1.8% relative humidity,
+0.2 degree Celsius) compared with the SHT21 (2.0% relative humidity,
+0.3 degree Celsius).
+
+The devices communicate with the I2C protocol. All sensors are set to the same
+I2C address 0x40, so an entry with I2C_BOARD_INFO("sht21", 0x40) can be used
+in the board setup code.
+
+sysfs-Interface
+---------------
+
+temp1_input - temperature input
+humidity1_input - humidity input
+
+Notes
+-----
+
+The driver uses the default resolution settings of 12 bit for humidity and 14
+bit for temperature, which results in typical measurement times of 22 ms for
+humidity and 66 ms for temperature. To keep self heating below 0.1 degree
+Celsius, the device should not be active for more than 10% of the time,
+e.g. maximum two measurements per second at the given resolution.
+
+Different resolutions, the on-chip heater, using the CRC checksum and reading
+the serial number are not supported yet.
index 645699010551927482d0beaa81d558b1a5ce8efb..c6559f15358933cb2ab74a49d70a34ce90e34e91 100644 (file)
@@ -384,10 +384,20 @@ curr[1-*]_min     Current min value.
                Unit: milliampere
                RW
 
+curr[1-*]_lcrit        Current critical low value
+               Unit: milliampere
+               RW
+
+curr[1-*]_crit Current critical high value.
+               Unit: milliampere
+               RW
+
 curr[1-*]_input        Current input value
                Unit: milliampere
                RO
 
+Also see the Alarms section for status flags associated with currents.
+
 *********
 * Power *
 *********
@@ -450,13 +460,6 @@ power[1-*]_accuracy                Accuracy of the power meter.
                                Unit: Percent
                                RO
 
-power[1-*]_alarm               1 if the system is drawing more power than the
-                               cap allows; 0 otherwise.  A poll notification is
-                               sent to this file when the power use exceeds the
-                               cap.  This file only appears if the cap is known
-                               to be enforced by hardware.
-                               RO
-
 power[1-*]_cap                 If power use rises above this limit, the
                                system should take action to reduce power use.
                                A poll notification is sent to this file if the
@@ -479,6 +482,20 @@ power[1-*]_cap_min         Minimum cap that can be set.
                                Unit: microWatt
                                RO
 
+power[1-*]_max                 Maximum power.
+                               Unit: microWatt
+                               RW
+
+power[1-*]_crit                        Critical maximum power.
+                               If power rises to or above this limit, the
+                               system is expected take drastic action to reduce
+                               power consumption, such as a system shutdown or
+                               a forced powerdown of some devices.
+                               Unit: microWatt
+                               RW
+
+Also see the Alarms section for status flags associated with power readings.
+
 **********
 * Energy *
 **********
@@ -488,6 +505,15 @@ energy[1-*]_input          Cumulative energy use
                                RO
 
 
+************
+* Humidity *
+************
+
+humidity[1-*]_input            Humidity
+                               Unit: milli-percent (per cent mille, pcm)
+                               RO
+
+
 **********
 * Alarms *
 **********
@@ -501,6 +527,7 @@ implementation.
 
 in[0-*]_alarm
 curr[1-*]_alarm
+power[1-*]_alarm
 fan[1-*]_alarm
 temp[1-*]_alarm
                Channel alarm
@@ -512,12 +539,20 @@ OR
 
 in[0-*]_min_alarm
 in[0-*]_max_alarm
+in[0-*]_lcrit_alarm
+in[0-*]_crit_alarm
 curr[1-*]_min_alarm
 curr[1-*]_max_alarm
+curr[1-*]_lcrit_alarm
+curr[1-*]_crit_alarm
+power[1-*]_cap_alarm
+power[1-*]_max_alarm
+power[1-*]_crit_alarm
 fan[1-*]_min_alarm
 fan[1-*]_max_alarm
 temp[1-*]_min_alarm
 temp[1-*]_max_alarm
+temp[1-*]_lcrit_alarm
 temp[1-*]_crit_alarm
 temp[1-*]_emergency_alarm
                Limit alarm
index 1e5165aa9e4ef79eb007d39203524722aa7d21bb..4a990317b84a7c60cac5b507a4efa682ca0ad4b7 100644 (file)
@@ -73,6 +73,14 @@ Specify the output directory when building the kernel.
 The output directory can also be specified using "O=...".
 Setting "O=..." takes precedence over KBUILD_OUTPUT.
 
+KBUILD_DEBARCH
+--------------------------------------------------
+For the deb-pkg target, allows overriding the normal heuristics deployed by
+deb-pkg. Normally deb-pkg attempts to guess the right architecture based on
+the UTS_MACHINE variable, and on some architectures also the kernel config.
+The value of KBUILD_DEBARCH is assumed (not checked) to be a valid Debian
+architecture.
+
 ARCH
 --------------------------------------------------
 Set ARCH to the architecture to be built.
index 2fe93ca7c77c4c97bf9252308e734b595f83c4b8..b507d61fd41cd6a20157dca27f38a28b98f4fa1d 100644 (file)
@@ -112,7 +112,6 @@ applicable everywhere (see syntax).
        (no prompts anywhere) and for symbols with no dependencies.
        That will limit the usefulness but on the other hand avoid
        the illegal configurations all over.
-       kconfig should one day warn about such things.
 
 - numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
   This allows to limit the range of possible input values for int
@@ -268,7 +267,7 @@ separate list of options.
 
 choices:
 
-       "choice"
+       "choice" [symbol]
        <choice options>
        <choice block>
        "endchoice"
@@ -282,6 +281,10 @@ single driver can be compiled/loaded into the kernel, but all drivers
 can be compiled as modules.
 A choice accepts another option "optional", which allows to set the
 choice to 'n' and no entry needs to be selected.
+If no [symbol] is associated with a choice, then you can not have multiple
+definitions of that choice. If a [symbol] is associated to the choice,
+then you may define the same choice (ie. with the same entries) in another
+place.
 
 comment:
 
index 0ef00bd6e54d4a7c4bdda4b230f575b4a759a58a..86e3cd0d26a087f80024636ab98f37d6879a6339 100644 (file)
@@ -1136,6 +1136,21 @@ When kbuild executes, the following steps are followed (roughly):
              resulting in the target file being recompiled for no
              obvious reason.
 
+    dtc
+       Create flattend device tree blob object suitable for linking
+       into vmlinux. Device tree blobs linked into vmlinux are placed
+       in an init section in the image. Platform code *must* copy the
+       blob to non-init memory prior to calling unflatten_device_tree().
+
+       Example:
+               #arch/x86/platform/ce4100/Makefile
+               clean-files := *dtb.S
+
+               DTC_FLAGS := -p 1024
+               obj-y += foo.dtb.o
+
+               $(obj)/%.dtb: $(src)/%.dts
+                       $(call cmd,dtc)
 
 --- 6.7 Custom kbuild commands
 
diff --git a/Documentation/keys-trusted-encrypted.txt b/Documentation/keys-trusted-encrypted.txt
new file mode 100644 (file)
index 0000000..8fb79bc
--- /dev/null
@@ -0,0 +1,145 @@
+                       Trusted and Encrypted Keys
+
+Trusted and Encrypted Keys are two new key types added to the existing kernel
+key ring service.  Both of these new types are variable length symmetic keys,
+and in both cases all keys are created in the kernel, and user space sees,
+stores, and loads only encrypted blobs.  Trusted Keys require the availability
+of a Trusted Platform Module (TPM) chip for greater security, while Encrypted
+Keys can be used on any system.  All user level blobs, are displayed and loaded
+in hex ascii for convenience, and are integrity verified.
+
+Trusted Keys use a TPM both to generate and to seal the keys.  Keys are sealed
+under a 2048 bit RSA key in the TPM, and optionally sealed to specified PCR
+(integrity measurement) values, and only unsealed by the TPM, if PCRs and blob
+integrity verifications match.  A loaded Trusted Key can be updated with new
+(future) PCR values, so keys are easily migrated to new pcr values, such as
+when the kernel and initramfs are updated.  The same key can have many saved
+blobs under different PCR values, so multiple boots are easily supported.
+
+By default, trusted keys are sealed under the SRK, which has the default
+authorization value (20 zeros).  This can be set at takeownership time with the
+trouser's utility: "tpm_takeownership -u -z".
+
+Usage:
+    keyctl add trusted name "new keylen [options]" ring
+    keyctl add trusted name "load hex_blob [pcrlock=pcrnum]" ring
+    keyctl update key "update [options]"
+    keyctl print keyid
+
+    options:
+       keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
+       keyauth=          ascii hex auth for sealing key default 0x00...i
+                 (40 ascii zeros)
+       blobauth=  ascii hex auth for sealed data default 0x00...
+                 (40 ascii zeros)
+       blobauth=  ascii hex auth for sealed data default 0x00...
+                 (40 ascii zeros)
+       pcrinfo=          ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
+       pcrlock=          pcr number to be extended to "lock" blob
+       migratable= 0|1 indicating permission to reseal to new PCR values,
+                   default 1 (resealing allowed)
+
+"keyctl print" returns an ascii hex copy of the sealed key, which is in standard
+TPM_STORED_DATA format.  The key length for new keys are always in bytes.
+Trusted Keys can be 32 - 128 bytes (256 - 1024 bits), the upper limit is to fit
+within the 2048 bit SRK (RSA) keylength, with all necessary structure/padding.
+
+Encrypted keys do not depend on a TPM, and are faster, as they use AES for
+encryption/decryption.  New keys are created from kernel generated random
+numbers, and are encrypted/decrypted using a specified 'master' key.  The
+'master' key can either be a trusted-key or user-key type.  The main
+disadvantage of encrypted keys is that if they are not rooted in a trusted key,
+they are only as secure as the user key encrypting them.  The master user key
+should therefore be loaded in as secure a way as possible, preferably early in
+boot.
+
+Usage:
+  keyctl add encrypted name "new key-type:master-key-name keylen" ring
+  keyctl add encrypted name "load hex_blob" ring
+  keyctl update keyid "update key-type:master-key-name"
+
+where 'key-type' is either 'trusted' or 'user'.
+
+Examples of trusted and encrypted key usage:
+
+Create and save a trusted key named "kmk" of length 32 bytes:
+
+    $ keyctl add trusted kmk "new 32" @u
+    440502848
+
+    $ keyctl show
+    Session Keyring
+           -3 --alswrv    500   500  keyring: _ses
+     97833714 --alswrv    500    -1   \_ keyring: _uid.500
+    440502848 --alswrv    500   500       \_ trusted: kmk
+
+    $ keyctl print 440502848
+    0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
+    3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
+    27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
+    a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
+    d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
+    dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
+    f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
+    e4a8aea2b607ec96931e6f4d4fe563ba
+
+    $ keyctl pipe 440502848 > kmk.blob
+
+Load a trusted key from the saved blob:
+
+    $ keyctl add trusted kmk "load `cat kmk.blob`" @u
+    268728824
+
+    $ keyctl print 268728824
+    0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
+    3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
+    27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
+    a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
+    d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
+    dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
+    f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
+    e4a8aea2b607ec96931e6f4d4fe563ba
+
+Reseal a trusted key under new pcr values:
+
+    $ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`"
+    $ keyctl print 268728824
+    010100000000002c0002800093c35a09b70fff26e7a98ae786c641e678ec6ffb6b46d805
+    77c8a6377aed9d3219c6dfec4b23ffe3000001005d37d472ac8a44023fbb3d18583a4f73
+    d3a076c0858f6f1dcaa39ea0f119911ff03f5406df4f7f27f41da8d7194f45c9f4e00f2e
+    df449f266253aa3f52e55c53de147773e00f0f9aca86c64d94c95382265968c354c5eab4
+    9638c5ae99c89de1e0997242edfb0b501744e11ff9762dfd951cffd93227cc513384e7e6
+    e782c29435c7ec2edafaa2f4c1fe6e7a781b59549ff5296371b42133777dcc5b8b971610
+    94bc67ede19e43ddb9dc2baacad374a36feaf0314d700af0a65c164b7082401740e489c9
+    7ef6a24defe4846104209bf0c3eced7fa1a672ed5b125fc9d8cd88b476a658a4434644ef
+    df8ae9a178e9f83ba9f08d10fa47e4226b98b0702f06b3b8
+
+Create and save an encrypted key "evm" using the above trusted key "kmk":
+
+    $ keyctl add encrypted evm "new trusted:kmk 32" @u
+    159771175
+
+    $ keyctl print 159771175
+    trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382dbbc55
+    be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e024717c64
+    5972dcb82ab2dde83376d82b2e3c09ffc
+
+    $ keyctl pipe 159771175 > evm.blob
+
+Load an encrypted key "evm" from saved blob:
+
+    $ keyctl add encrypted evm "load `cat evm.blob`" @u
+    831684262
+
+    $ keyctl print 831684262
+    trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382dbbc55
+    be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e024717c64
+    5972dcb82ab2dde83376d82b2e3c09ffc
+
+
+The initial consumer of trusted keys is EVM, which at boot time needs a high
+quality symmetric key for HMAC protection of file metadata.  The use of a
+trusted key provides strong guarantees that the EVM key has not been
+compromised by a user level problem, and when sealed to specific boot PCR
+values, protects against boot and offline attacks.  Other uses for trusted and
+encrypted keys, such as for disk and file encryption are anticipated.
index f2481cabffcb0df8362f0384507133154de01afe..951eb9f1e0404d549be909b5fe8fec61c4f61389 100644 (file)
@@ -39,8 +39,9 @@ INSTALL_HDR_PATH indicates where to install the headers.  It defaults to
 The command "make headers_install_all" exports headers for all architectures
 simultaneously.  (This is mostly of interest to distribution maintainers,
 who create an architecture-independent tarball from the resulting include
-directory.)  Remember to provide the appropriate linux/asm directory via "mv"
-or "ln -s" before building a C library with headers exported this way.
+directory.)  You also can use HDR_ARCH_LIST to specify list of architectures.
+Remember to provide the appropriate linux/asm directory via "mv" or "ln -s"
+before building a C library with headers exported this way.
 
 The kernel header export infrastructure is maintained by David Woodhouse
 <dwmw2@infradead.org>.
index 7f7a737f7f9fd785deacaf4f3aaaf56d87a21c11..638afdf4d6b8ec29735857ab949074a2bd58fb75 100644 (file)
@@ -23,10 +23,10 @@ Once you have resolved the suspend/resume-related problems with your test system
 without the new driver, you are ready to test it:
 
 a) Build the driver as a module, load it and try the test modes of hibernation
-   (see: Documents/power/basic-pm-debugging.txt, 1).
+   (see: Documentation/power/basic-pm-debugging.txt, 1).
 
 b) Load the driver and attempt to hibernate in the "reboot", "shutdown" and
-   "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).
+   "platform" modes (see: Documentation/power/basic-pm-debugging.txt, 1).
 
 c) Compile the driver directly into the kernel and try the test modes of
    hibernation.
@@ -34,12 +34,12 @@ c) Compile the driver directly into the kernel and try the test modes of
 d) Attempt to hibernate with the driver compiled directly into the kernel
    in the "reboot", "shutdown" and "platform" modes.
 
-e) Try the test modes of suspend (see: Documents/power/basic-pm-debugging.txt,
+e) Try the test modes of suspend (see: Documentation/power/basic-pm-debugging.txt,
    2).  [As far as the STR tests are concerned, it should not matter whether or
    not the driver is built as a module.]
 
 f) Attempt to suspend to RAM using the s2ram tool with the driver loaded
-   (see: Documents/power/basic-pm-debugging.txt, 2).
+   (see: Documentation/power/basic-pm-debugging.txt, 2).
 
 Each of the above tests should be repeated several times and the STD tests
 should be mixed with the STR tests.  If any of them fails, the driver cannot be
index 41cc7b30d7ddaff700a198b590eb91047d90d0d0..ffe55ffa540a1b59a6e37979e86b842022cc2b56 100644 (file)
@@ -50,6 +50,15 @@ type's callbacks are not defined) of given device.  The bus type, device type
 and device class callbacks are referred to as subsystem-level callbacks in what
 follows.
 
+By default, the callbacks are always invoked in process context with interrupts
+enabled.  However, subsystems can use the pm_runtime_irq_safe() helper function
+to tell the PM core that a device's ->runtime_suspend() and ->runtime_resume()
+callbacks should be invoked in atomic context with interrupts disabled
+(->runtime_idle() is still invoked the default way).  This implies that these
+callback routines must not block or sleep, but it also means that the
+synchronous helper functions listed at the end of Section 4 can be used within
+an interrupt handler or in an atomic context.
+
 The subsystem-level suspend callback is _entirely_ _responsible_ for handling
 the suspend of the device as appropriate, which may, but need not include
 executing the device driver's own ->runtime_suspend() callback (from the
@@ -237,6 +246,10 @@ defined in include/linux/pm.h:
       Section 8); it may be modified only by the pm_runtime_no_callbacks()
       helper function
 
+  unsigned int irq_safe;
+    - indicates that the ->runtime_suspend() and ->runtime_resume() callbacks
+      will be invoked with the spinlock held and interrupts disabled
+
   unsigned int use_autosuspend;
     - indicates that the device's driver supports delayed autosuspend (see
       Section 9); it may be modified only by the
@@ -344,6 +357,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
     - decrement the device's usage counter; if the result is 0 then run
       pm_runtime_idle(dev) and return its result
 
+  int pm_runtime_put_sync_suspend(struct device *dev);
+    - decrement the device's usage counter; if the result is 0 then run
+      pm_runtime_suspend(dev) and return its result
+
   int pm_runtime_put_sync_autosuspend(struct device *dev);
     - decrement the device's usage counter; if the result is 0 then run
       pm_runtime_autosuspend(dev) and return its result
@@ -397,6 +414,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
       PM attributes from /sys/devices/.../power (or prevent them from being
       added when the device is registered)
 
+  void pm_runtime_irq_safe(struct device *dev);
+    - set the power.irq_safe flag for the device, causing the runtime-PM
+      suspend and resume callbacks (but not the idle callback) to be invoked
+      with interrupts disabled
+
   void pm_runtime_mark_last_busy(struct device *dev);
     - set the power.last_busy field to the current time
 
@@ -438,6 +460,15 @@ pm_runtime_suspended()
 pm_runtime_mark_last_busy()
 pm_runtime_autosuspend_expiration()
 
+If pm_runtime_irq_safe() has been called for a device then the following helper
+functions may also be used in interrupt context:
+
+pm_runtime_suspend()
+pm_runtime_autosuspend()
+pm_runtime_resume()
+pm_runtime_get_sync()
+pm_runtime_put_sync_suspend()
+
 5. Run-time PM Initialization, Device Probing and Removal
 
 Initially, the run-time PM is disabled for all devices, which means that the
diff --git a/Documentation/powerpc/dts-bindings/eeprom.txt b/Documentation/powerpc/dts-bindings/eeprom.txt
new file mode 100644 (file)
index 0000000..4342c10
--- /dev/null
@@ -0,0 +1,28 @@
+EEPROMs (I2C)
+
+Required properties:
+
+  - compatible : should be "<manufacturer>,<type>"
+                If there is no specific driver for <manufacturer>, a generic
+                driver based on <type> is selected. Possible types are:
+                24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64,
+                24c128, 24c256, 24c512, 24c1024, spd
+
+  - reg : the I2C address of the EEPROM
+
+Optional properties:
+
+  - pagesize : the length of the pagesize for writing. Please consult the
+               manual of your device, that value varies a lot. A wrong value
+              may result in data loss! If not specified, a safety value of
+              '1' is used which will be very slow.
+
+  - read-only: this parameterless property disables writes to the eeprom
+
+Example:
+
+eeprom@52 {
+       compatible = "atmel,24c32";
+       reg = <0x52>;
+       pagesize = <32>;
+};
index 6bb916d57c957754fd9b4915c4d1a42e3a4cc8ac..68a4fe3818a157a806e3c35a492218683085b8cb 100644 (file)
@@ -19,7 +19,7 @@ Declaring PXA2xx Master Controllers
 -----------------------------------
 Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a
 "platform device".  The master configuration is passed to the driver via a table
-found in arch/arm/mach-pxa/include/mach/pxa2xx_spi.h:
+found in include/linux/spi/pxa2xx_spi.h:
 
 struct pxa2xx_spi_master {
        enum pxa_ssp_type ssp_type;
@@ -94,7 +94,7 @@ using the "spi_board_info" structure found in "linux/spi/spi.h". See
 
 Each slave device attached to the PXA must provide slave specific configuration
 information via the structure "pxa2xx_spi_chip" found in
-"arch/arm/mach-pxa/include/mach/pxa2xx_spi.h".  The pxa2xx_spi master controller driver
+"include/linux/spi/pxa2xx_spi.h".  The pxa2xx_spi master controller driver
 will uses the configuration whenever the driver communicates with the slave
 device. All fields are optional.
 
index 209e1584c3dc25e8e1af61a3061c779a28f5d11e..574067194f3870cd4c36d915afb8ae04f9004b96 100644 (file)
@@ -219,7 +219,7 @@ dmesg_restrict:
 This toggle indicates whether unprivileged users are prevented from using
 dmesg(8) to view messages from the kernel's log buffer.  When
 dmesg_restrict is set to (0) there are no restrictions.  When
-dmesg_restrict is set set to (1), users must have CAP_SYS_ADMIN to use
+dmesg_restrict is set set to (1), users must have CAP_SYSLOG to use
 dmesg(8).
 
 The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default
index 9dcff328b964b1889293518a064031bb73930ab3..3fa4d0668864d98ea8b2a586c8ec3f708cc1d716 100644 (file)
@@ -2,7 +2,7 @@
 obj- := dummy.o
 
 # List of programs to build
-hostprogs-y := slabinfo page-types hugepage-mmap hugepage-shm map_hugetlb
+hostprogs-y := page-types hugepage-mmap hugepage-shm map_hugetlb
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
index 78d317c545b9df0a75b97e4b6b00842f558b2feb..9e4d4ca690e2633bd7b1f6d507b28f26c288a6f2 100644 (file)
@@ -4268,6 +4268,7 @@ NILFS2 FILESYSTEM
 M:     KONISHI Ryusuke <konishi.ryusuke@lab.ntt.co.jp>
 L:     linux-nilfs@vger.kernel.org
 W:     http://www.nilfs.org/en/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2.git
 S:     Supported
 F:     Documentation/filesystems/nilfs2.txt
 F:     fs/nilfs2/
@@ -4653,6 +4654,16 @@ S:       Maintained
 F:     crypto/pcrypt.c
 F:     include/crypto/pcrypt.h
 
+PER-CPU MEMORY ALLOCATOR
+M:     Tejun Heo <tj@kernel.org>
+M:     Christoph Lameter <cl@linux-foundation.org>
+L:     linux-kernel@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu.git
+S:     Maintained
+F:     include/linux/percpu*.h
+F:     mm/percpu*.c
+F:     arch/*/include/asm/percpu.h
+
 PER-TASK DELAY ACCOUNTING
 M:     Balbir Singh <balbir@linux.vnet.ibm.com>
 S:     Maintained
@@ -5919,7 +5930,8 @@ F:        drivers/net/tlan.*
 TOMOYO SECURITY MODULE
 M:     Kentaro Takeda <takedakn@nttdata.co.jp>
 M:     Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
-L:     tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and users in English)
+L:     tomoyo-dev-en@lists.sourceforge.jp (subscribers-only, for developers in English)
+L:     tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for users in English)
 L:     tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
 L:     tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
 W:     http://tomoyo.sourceforge.jp/
index 74b25559f831c5c48150789ed3230921635e0ae0..6a457690d10be4106188df33dadd55f9d512230e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -224,6 +224,7 @@ ifeq ($(ARCH),m68knommu)
 endif
 
 KCONFIG_CONFIG ?= .config
+export KCONFIG_CONFIG
 
 # SHELL used by kbuild
 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
index 2652af124acd941bcb2f7d5bcefa88fe8a0721a2..a5f8a80c1f281112513a404eebbed824e9360dd2 100644 (file)
@@ -412,12 +412,7 @@ static struct resource dm355_spi0_resources[] = {
 static struct davinci_spi_platform_data dm355_spi0_pdata = {
        .version        = SPI_VERSION_1,
        .num_chipselect = 2,
-       .clk_internal   = 1,
-       .cs_hold        = 1,
-       .intr_level     = 0,
-       .poll_mode      = 1,    /* 0 -> interrupt mode 1-> polling mode */
-       .c2tdelay       = 0,
-       .t2cdelay       = 0,
+       .cshold_bug     = true,
 };
 static struct platform_device dm355_spi0_device = {
        .name = "spi_davinci",
index c466d710d3c103cef9f64445f2e994bcdb4551ca..02d2cc380df730bec88fb6fe428da6dac2c0139f 100644 (file)
@@ -625,12 +625,6 @@ static u64 dm365_spi0_dma_mask = DMA_BIT_MASK(32);
 static struct davinci_spi_platform_data dm365_spi0_pdata = {
        .version        = SPI_VERSION_1,
        .num_chipselect = 2,
-       .clk_internal   = 1,
-       .cs_hold        = 1,
-       .intr_level     = 0,
-       .poll_mode      = 1,    /* 0 -> interrupt mode 1-> polling mode */
-       .c2tdelay       = 0,
-       .t2cdelay       = 0,
 };
 
 static struct resource dm365_spi0_resources[] = {
index 910efbf099c097244a8bbb97c9e70540c6d128f7..38f4da5ca135cfa32adeda31fc29bd27e04d8405 100644 (file)
 #ifndef __ARCH_ARM_DAVINCI_SPI_H
 #define __ARCH_ARM_DAVINCI_SPI_H
 
+#define SPI_INTERN_CS  0xFF
+
 enum {
        SPI_VERSION_1, /* For DM355/DM365/DM6467 */
        SPI_VERSION_2, /* For DA8xx */
 };
 
+/**
+ * davinci_spi_platform_data - Platform data for SPI master device on DaVinci
+ *
+ * @version:   version of the SPI IP. Different DaVinci devices have slightly
+ *             varying versions of the same IP.
+ * @num_chipselect: number of chipselects supported by this SPI master
+ * @intr_line: interrupt line used to connect the SPI IP to the ARM interrupt
+ *             controller withn the SoC. Possible values are 0 and 1.
+ * @chip_sel:  list of GPIOs which can act as chip-selects for the SPI.
+ *             SPI_INTERN_CS denotes internal SPI chip-select. Not necessary
+ *             to populate if all chip-selects are internal.
+ * @cshold_bug:        set this to true if the SPI controller on your chip requires
+ *             a write to CSHOLD bit in between transfers (like in DM355).
+ */
 struct davinci_spi_platform_data {
        u8      version;
        u8      num_chipselect;
+       u8      intr_line;
+       u8      *chip_sel;
+       bool    cshold_bug;
+};
+
+/**
+ * davinci_spi_config - Per-chip-select configuration for SPI slave devices
+ *
+ * @wdelay:    amount of delay between transmissions. Measured in number of
+ *             SPI module clocks.
+ * @odd_parity:        polarity of parity flag at the end of transmit data stream.
+ *             0 - odd parity, 1 - even parity.
+ * @parity_enable: enable transmission of parity at end of each transmit
+ *             data stream.
+ * @io_type:   type of IO transfer. Choose between polled, interrupt and DMA.
+ * @timer_disable: disable chip-select timers (setup and hold)
+ * @c2tdelay:  chip-select setup time. Measured in number of SPI module clocks.
+ * @t2cdelay:  chip-select hold time. Measured in number of SPI module clocks.
+ * @t2edelay:  transmit data finished to SPI ENAn pin inactive time. Measured
+ *             in number of SPI clocks.
+ * @c2edelay:  chip-select active to SPI ENAn signal active time. Measured in
+ *             number of SPI clocks.
+ */
+struct davinci_spi_config {
        u8      wdelay;
        u8      odd_parity;
        u8      parity_enable;
-       u8      wait_enable;
+#define SPI_IO_TYPE_INTR       0
+#define SPI_IO_TYPE_POLL       1
+#define SPI_IO_TYPE_DMA                2
+       u8      io_type;
        u8      timer_disable;
-       u8      clk_internal;
-       u8      cs_hold;
-       u8      intr_level;
-       u8      poll_mode;
-       u8      use_dma;
        u8      c2tdelay;
        u8      t2cdelay;
+       u8      t2edelay;
+       u8      c2edelay;
 };
 
 #endif /* __ARCH_ARM_DAVINCI_SPI_H */
index f1a7703d771bf7ed4047d4812d6cac0ef4802d3d..93f59f877fc602887435fca577780a8420bedba8 100644 (file)
 #include <linux/mtd/nand-gpio.h>
 
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 
 #include <mach/pxa25x.h>
-#include <mach/pxa2xx_spi.h>
 
 #include "generic.h"
 
index a9926bb75922318a9f193752637d6505bc9429a5..b88d601a80904baddb4c787dcee19194dab4bdf0 100644 (file)
 #include <video/mbxfb.h>
 
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/spi/libertas_spi.h>
 
 #include <mach/pxa27x.h>
 #include <mach/ohci.h>
 #include <mach/mmc.h>
-#include <mach/pxa2xx_spi.h>
 
 #include "generic.h"
 
index 9f3e5af0a0db342170ee957ed23bf7a4609a3461..a5452a3a276d87f741c00740450557e2fb8d6251 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/corgi_lcd.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/mtd/sharpsl.h>
 #include <linux/input/matrix_keypad.h>
 #include <video/w100fb.h>
@@ -48,7 +49,6 @@
 #include <mach/irda.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/corgi.h>
 #include <mach/sharpsl_pm.h>
 
index 022c2fa4af04063ebe2334dc19754d4597e7de05..4c766e3b4af3174c716cbe6a5233ebf928f0bb80 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/spi/pxa2xx_spi.h>
 
 #include <asm/pmu.h>
 #include <mach/udc.h>
@@ -12,7 +13,6 @@
 #include <mach/irda.h>
 #include <mach/ohci.h>
 #include <plat/pxa27x_keypad.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/camera.h>
 #include <mach/audio.h>
 #include <mach/hardware.h>
index 4cefd1d18afd5c8d3be2829129e771ced03c3859..a78bb3097739573478cae0a6c69760d31c709aca 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/tdo24m.h>
 #include <linux/spi/libertas_spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/power_supply.h>
 #include <linux/apm-emulation.h>
 #include <linux/i2c.h>
@@ -46,7 +47,6 @@
 #include <plat/pxa27x_keypad.h>
 #include <plat/i2c.h>
 #include <mach/camera.h>
-#include <mach/pxa2xx_spi.h>
 
 #include "generic.h"
 #include "devices.h"
index cacb21b7014db58a56a6c1c3e7457fdad9cb8669..a908e0a5f3966984a9c71bc07eae305b5aa0da83 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/regulator/max1586.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/usb/gpio_vbus.h>
 
 #include <mach/hardware.h>
@@ -43,7 +44,6 @@
 #include <mach/hx4700.h>
 #include <plat/i2c.h>
 #include <mach/irda.h>
-#include <mach/pxa2xx_spi.h>
 
 #include <video/platform_lcd.h>
 #include <video/w100fb.h>
index ac6ee12e400e8870dacf58a4c32b8f7ba82802bd..6cedc81da3bc1b806dd2cec3356d37de0a3c581c 100644 (file)
@@ -24,7 +24,7 @@
 #include <mach/mxm8x10.h>
 
 #include <linux/spi/spi.h>
-#include <mach/pxa2xx_spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/can/platform/mcp251x.h>
 
 #include "generic.h"
diff --git a/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h b/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h
deleted file mode 100644 (file)
index b87cecd..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef PXA2XX_SPI_H_
-#define PXA2XX_SPI_H_
-
-#define PXA2XX_CS_ASSERT (0x01)
-#define PXA2XX_CS_DEASSERT (0x02)
-
-/* device.platform_data for SSP controller devices */
-struct pxa2xx_spi_master {
-       u32 clock_enable;
-       u16 num_chipselect;
-       u8 enable_dma;
-};
-
-/* spi_board_info.controller_data for SPI slave devices,
- * copied to spi_device.platform_data ... mostly for dma tuning
- */
-struct pxa2xx_spi_chip {
-       u8 tx_threshold;
-       u8 rx_threshold;
-       u8 dma_burst_size;
-       u32 timeout;
-       u8 enable_loopback;
-       int gpio_cs;
-       void (*cs_control)(u32 command);
-};
-
-extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info);
-
-#endif /*PXA2XX_SPI_H_*/
index 719c260597e7c01463f757c74b810528fc3e6fce..ccb7bfad17ca94e7dddd15eea58ed0a3629175b8 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/smc91x.h>
 #include <linux/i2c.h>
 #include <linux/leds.h>
@@ -42,7 +43,6 @@
 #include <mach/pxa300.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
-#include <mach/pxa2xx_spi.h>
 #include <plat/pxa27x_keypad.h>
 #include <mach/littleton.h>
 #include <plat/i2c.h>
index d3375486c8cdf7626743886ab25718557baa6c5a..3072dbea5c1f7da4d8524bceaa6f2f8f09f2ce9f 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
-#include <mach/pxa2xx_spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 
 #include <asm/setup.h>
 #include <asm/memory.h>
index 8547c9abc40a2e1500ba348682aed7f395596693..1fc8a66407ae1fef0ba0fe5ce1bcae925e854eda 100644 (file)
 #include <linux/mtd/physmap.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/max7301.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/leds.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/pxa27x.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/pcm027.h>
 #include "generic.h"
 
index 8451790cb48d9785d4d5fbccbef1eba12debd268..4f0ff1ab623d11ccbfe81968a179406f74501a46 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/mtd/sharpsl.h>
 
 #include <mach/hardware.h>
@@ -43,7 +44,6 @@
 #include <mach/irda.h>
 #include <mach/poodle.h>
 #include <mach/pxafb.h>
-#include <mach/pxa2xx_spi.h>
 #include <plat/i2c.h>
 
 #include <asm/hardware/scoop.h>
index 8fed027b12dcee3edd70cc9e9968e465e7a84dd1..e68d46d415f340852ed27d59820acd326a6452f7 100644 (file)
@@ -579,7 +579,8 @@ static int sharpsl_ac_check(void)
 static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
 {
        sharpsl_pm.flags |= SHARPSL_SUSPENDED;
-       flush_scheduled_work();
+       flush_delayed_work_sync(&toggle_charger);
+       flush_delayed_work_sync(&sharpsl_bat);
 
        if (sharpsl_pm.charge_mode == CHRG_ON)
                sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
index 0499a69e76733d07aedc78f8bf9e95b324f04392..0bc938729c4cf534255dc92ab098ffcb058162e0 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/corgi_lcd.h>
-#include <linux/mtd/physmap.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/mtd/sharpsl.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/regulator/machine.h>
@@ -42,7 +42,6 @@
 #include <mach/mmc.h>
 #include <mach/ohci.h>
 #include <mach/pxafb.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/spitz.h>
 #include <mach/sharpsl_pm.h>
 #include <mach/smemc.h>
index 3498a1423943474307a207fc0f526f9007848cd4..9a14fdb83c82b3517ba522cba936fab646c3148f 100644 (file)
 #include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/pxa27x-udc.h>
 #include <mach/smemc.h>
 
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/mfd/da903x.h>
 #include <linux/sht15.h>
 
index 57d61ee9b22604d82a911264b4ebbbebfcf585ab..af152e70cfcfc09d7e8c29eb39388de04b3cd9e9 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/gpio.h>
 #include <linux/pda_power.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/input/matrix_keypad.h>
 
 #include <asm/setup.h>
@@ -44,7 +45,6 @@
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/tosa_bt.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/audio.h>
 #include <mach/smemc.h>
 
index 43fc9ca14594995b43d68cba6ec9c0471dc833fe..423261d63d073213c5ca0f4d01e5fa25e237f2f1 100644 (file)
@@ -40,7 +40,6 @@
 #include <asm/mach/flash.h>
 
 #include <mach/pxa27x.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/trizeps4.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
index 527c2a1ed310e0f5e1d83dec0438e301be20156c..a323e076129e933eae1164ce7bde102d98189deb 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/z2_battery.h>
 #include <linux/dma-mapping.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/spi/libertas_spi.h>
 #include <linux/spi/lms283gf05.h>
 #include <linux/power_supply.h>
@@ -38,7 +39,6 @@
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <plat/pxa27x_keypad.h>
-#include <mach/pxa2xx_spi.h>
 
 #include <plat/i2c.h>
 
index c87f2b35ee05223702c50d8df0e8e02d9b66e467..bf034c7670ddf867774ffaf65103e1e16a70d487 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/dm9000.h>
 #include <linux/mmc/host.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
@@ -41,7 +42,6 @@
 #include <mach/pxa27x-udc.h>
 #include <mach/udc.h>
 #include <mach/pxafb.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/mfp-pxa27x.h>
 #include <mach/pm.h>
 #include <mach/audio.h>
index c6357e554aba91114cc01884602aa7914501938e..58b79809d20cd47a6a0579f91d49084d027f73e7 100644 (file)
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/io.h>
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
-#include <plat/ssp.h>
 
 static DEFINE_MUTEX(ssp_lock);
 static LIST_HEAD(ssp_list);
index 1ecc15bfe9d40b44a7d6225ba1b413640da2f460..25a8fc7f512e64ea7b1fe77af32febc7b53bb212 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/sysdev.h>
-#include <linux/kobject.h>
 #include <linux/sysfs.h>
 #include <linux/slab.h>
 
index 387d5ffdfd3aea4e9807349edb1a6d6852cbb221..5f5018a71a3db9c7bf6b57bcfbdcbb3bf1883d7a 100644 (file)
@@ -14,7 +14,7 @@ config MICROBLAZE
        select HAVE_DMA_API_DEBUG
        select TRACING_SUPPORT
        select OF
-       select OF_FLATTREE
+       select OF_EARLY_FLATTREE
 
 config SWAP
        def_bool n
index be01d78750d9c64dc44e74c8475ec720f19a791f..4c4e58ef0cb628ed3ca0f542536872036f93da02 100644 (file)
@@ -10,9 +10,6 @@ targets := linux.bin linux.bin.gz simpleImage.%
 
 OBJCOPYFLAGS := -O binary
 
-# Where the DTS files live
-dtstree         := $(srctree)/$(src)/dts
-
 # Ensure system.dtb exists
 $(obj)/linked_dtb.o: $(obj)/system.dtb
 
@@ -51,14 +48,11 @@ $(obj)/simpleImage.%: vmlinux FORCE
        $(call if_changed,strip)
        @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
-# Rule to build device tree blobs
-DTC = $(objtree)/scripts/dtc/dtc
 
 # Rule to build device tree blobs
-quiet_cmd_dtc = DTC     $@
-       cmd_dtc = $(DTC) -O dtb -o $(obj)/$*.dtb -b 0 -p 1024 $(dtstree)/$*.dts
+DTC_FLAGS := -p 1024
 
-$(obj)/%.dtb: $(dtstree)/%.dts FORCE
-       $(call if_changed,dtc)
+$(obj)/%.dtb: $(src)/dts/%.dts FORCE
+       $(call cmd,dtc)
 
 clean-files += *.dtb simpleImage.*.unstrip linux.bin.ub
index bdc38312ae4ae00b677328c1eab1524f3cfd75a8..2e72af078b059dadd7512967aa14d6bf51d0bd0f 100644 (file)
@@ -64,9 +64,6 @@ extern void kdump_move_device_tree(void);
 /* CPU OF node matching */
 struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
 
-/* Get the MAC address */
-extern const void *of_get_mac_address(struct device_node *np);
-
 /**
  * of_irq_map_pci - Resolve the interrupt for a PCI device
  * @pdev:      the device whose interrupt is to be resolved
index 99d9b61cccb592cb34985bf79fb777b0521a36bf..9ae24f4b882bfe792e6657c867c8af32b00908ee 100644 (file)
@@ -110,41 +110,3 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
        cells = prop ? *(u32 *)prop : of_n_size_cells(dn);
        *size = of_read_number(dma_window, cells);
 }
-
-/**
- * Search the device tree for the best MAC address to use.  'mac-address' is
- * checked first, because that is supposed to contain to "most recent" MAC
- * address. If that isn't set, then 'local-mac-address' is checked next,
- * because that is the default address.  If that isn't set, then the obsolete
- * 'address' is checked, just in case we're using an old device tree.
- *
- * Note that the 'address' property is supposed to contain a virtual address of
- * the register set, but some DTS files have redefined that property to be the
- * MAC address.
- *
- * All-zero MAC addresses are rejected, because those could be properties that
- * exist in the device tree, but were not set by U-Boot.  For example, the
- * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
- * addresses.  Some older U-Boots only initialized 'local-mac-address'.  In
- * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
- * but is all zeros.
-*/
-const void *of_get_mac_address(struct device_node *np)
-{
-       struct property *pp;
-
-       pp = of_find_property(np, "mac-address", NULL);
-       if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
-               return pp->value;
-
-       pp = of_find_property(np, "local-mac-address", NULL);
-       if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
-               return pp->value;
-
-       pp = of_find_property(np, "address", NULL);
-       if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
-               return pp->value;
-
-       return NULL;
-}
-EXPORT_SYMBOL(of_get_mac_address);
index 0a9b5b8b2a1935103ecf9d81a2367d0a0633f1e4..f489ec30e071aa1932c43d4149a1130b23ae0349 100644 (file)
@@ -2218,7 +2218,7 @@ config SECCOMP
 config USE_OF
        bool "Flattened Device Tree support"
        select OF
-       select OF_FLATTREE
+       select OF_EARLY_FLATTREE
        help
          Include support for flattened device tree machine descriptions.
 
index e625e9e034ae19abe973282a3d83952493e8b709..48fb4790bfec286f616e75a91129a185cc391162 100644 (file)
@@ -116,7 +116,7 @@ config PPC
        bool
        default y
        select OF
-       select OF_FLATTREE
+       select OF_EARLY_FLATTREE
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_DYNAMIC_FTRACE
        select HAVE_FUNCTION_TRACER
index fae8192c8fcce0a7069b1d7dff785f5fdda67273..96deec63bcf3db53b62251cba32183f3daffbf7e 100644 (file)
@@ -35,7 +35,7 @@ endif
 
 BOOTCFLAGS     += -I$(obj) -I$(srctree)/$(obj)
 
-DTS_FLAGS      ?= -p 1024
+DTC_FLAGS      ?= -p 1024
 
 $(obj)/4xx.o: BOOTCFLAGS += -mcpu=405
 $(obj)/ebony.o: BOOTCFLAGS += -mcpu=405
@@ -332,10 +332,8 @@ $(obj)/treeImage.%: vmlinux $(obj)/%.dtb $(wrapperbits)
        $(call if_changed,wrap,treeboot-$*,,$(obj)/$*.dtb)
 
 # Rule to build device tree blobs
-DTC = $(objtree)/scripts/dtc/dtc
-
-$(obj)/%.dtb: $(dtstree)/%.dts
-       $(DTC) -O dtb -o $(obj)/$*.dtb -b 0 $(DTS_FLAGS) $(dtstree)/$*.dts
+$(obj)/%.dtb: $(src)/dts/%.dts
+       $(call cmd,dtc)
 
 # If there isn't a platform selected then just strip the vmlinux.
 ifeq (,$(image-y))
index 9bb3d72c0e5aa3ecd9c9034cc54badbab92e7aee..2a56a0dbd1f7e1ae87b7bd10c6200158e49662fa 100644 (file)
@@ -33,7 +33,7 @@
        aliases {
                ethernet0 = &EMAC0;
                serial0 = &UART0;
-               serial1 = &UART1;
+               //serial1 = &UART1; --gcl missing UART1 label
        };
 
        cpus {
@@ -52,7 +52,7 @@
                        d-cache-size = <32768>;
                        dcr-controller;
                        dcr-access-method = "native";
-                       next-level-cache = <&L2C0>;
+                       //next-level-cache = <&L2C0>; --gcl missing L2C0 label
                };
        };
 
                                        /*RXEOB*/ 0x7 0x4
                                        /*SERR*/  0x3 0x4
                                        /*TXDE*/  0x4 0x4
-                                       /*RXDE*/  0x5 0x4
+                                       /*RXDE*/  0x5 0x4>;
                };
 
                POB0: opb {
                                                reg = <0x001a0000 0x00060000>;
                                        };
                                };
-                       }
+                       };
 
                        UART0: serial@ef600300 {
                                device_type = "serial";
index dd3860846f156402ea47bc618f6225414d31e3ba..ad3a4f4a2b048bbe7efdfa91f2783d9468df005c 100644 (file)
  * option) any later version.
  */
 
-/dts-v1/;
+/include/ "mpc5200b.dtsi"
 
 / {
        model = "schindler,cm5200";
        compatible = "schindler,cm5200";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       interrupt-parent = <&mpc5200_pic>;
-
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               PowerPC,5200@0 {
-                       device_type = "cpu";
-                       reg = <0>;
-                       d-cache-line-size = <32>;
-                       i-cache-line-size = <32>;
-                       d-cache-size = <0x4000>;                // L1, 16K
-                       i-cache-size = <0x4000>;                // L1, 16K
-                       timebase-frequency = <0>;       // from bootloader
-                       bus-frequency = <0>;            // from bootloader
-                       clock-frequency = <0>;          // from bootloader
-               };
-       };
-
-       memory {
-               device_type = "memory";
-               reg = <0x00000000 0x04000000>;  // 64MB
-       };
 
        soc5200@f0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc5200b-immr";
-               ranges = <0 0xf0000000 0x0000c000>;
-               reg = <0xf0000000 0x00000100>;
-               bus-frequency = <0>;            // from bootloader
-               system-frequency = <0>;         // from bootloader
-
-               cdm@200 {
-                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
-                       reg = <0x200 0x38>;
-               };
-
-               mpc5200_pic: interrupt-controller@500 {
-                       // 5200 interrupts are encoded into two levels;
-                       interrupt-controller;
-                       #interrupt-cells = <3>;
-                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
-                       reg = <0x500 0x80>;
-               };
-
                timer@600 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x600 0x10>;
-                       interrupts = <1 9 0>;
                        fsl,has-wdt;
                };
 
-               timer@610 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x610 0x10>;
-                       interrupts = <1 10 0>;
-               };
-
-               timer@620 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x620 0x10>;
-                       interrupts = <1 11 0>;
-               };
-
-               timer@630 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x630 0x10>;
-                       interrupts = <1 12 0>;
-               };
-
-               timer@640 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x640 0x10>;
-                       interrupts = <1 13 0>;
-               };
-
-               timer@650 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x650 0x10>;
-                       interrupts = <1 14 0>;
-               };
-
-               timer@660 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x660 0x10>;
-                       interrupts = <1 15 0>;
-               };
-
-               timer@670 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x670 0x10>;
-                       interrupts = <1 16 0>;
+               can@900 {
+                       status = "disabled";
                };
 
-               rtc@800 {       // Real time clock
-                       compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
-                       reg = <0x800 0x100>;
-                       interrupts = <1 5 0 1 6 0>;
+               can@980 {
+                       status = "disabled";
                };
 
-               gpio_simple: gpio@b00 {
-                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
-                       reg = <0xb00 0x40>;
-                       interrupts = <1 7 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
-               };
-
-               gpio_wkup: gpio@c00 {
-                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
-                       reg = <0xc00 0x40>;
-                       interrupts = <1 8 0 0 3 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
-               };
-
-               spi@f00 {
-                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-                       reg = <0xf00 0x20>;
-                       interrupts = <2 13 0 2 14 0>;
-               };
-
-               usb@1000 {
-                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
-                       reg = <0x1000 0xff>;
-                       interrupts = <2 6 0>;
-               };
-
-               dma-controller@1200 {
-                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
-                       reg = <0x1200 0x80>;
-                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
-                                     3 4 0  3 5 0  3 6 0  3 7 0
-                                     3 8 0  3 9 0  3 10 0  3 11 0
-                                     3 12 0  3 13 0  3 14 0  3 15 0>;
+               psc@2000 {              // PSC1
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
                };
 
-               xlb@1f00 {
-                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
-                       reg = <0x1f00 0x100>;
+               psc@2200 {              // PSC2
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
                };
 
-               serial@2000 {           // PSC1
+               psc@2400 {              // PSC3
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2000 0x100>;
-                       interrupts = <2 1 0>;
                };
 
-               serial@2200 {           // PSC2
-                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2200 0x100>;
-                       interrupts = <2 2 0>;
+               psc@2600 {              // PSC4
+                       status = "disabled";
                };
 
-               serial@2400 {           // PSC3
-                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2400 0x100>;
-                       interrupts = <2 3 0>;
+               psc@2800 {              // PSC5
+                       status = "disabled";
                };
 
-               serial@2c00 {           // PSC6
+               psc@2c00 {              // PSC6
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2c00 0x100>;
-                       interrupts = <2 4 0>;
                };
 
                ethernet@3000 {
-                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
-                       reg = <0x3000 0x400>;
-                       local-mac-address = [ 00 00 00 00 00 00 ];
-                       interrupts = <2 5 0>;
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
-                       reg = <0x3000 0x400>;       // fec range, since we need to setup fec interrupts
-                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-
                        phy0: ethernet-phy@0 {
                                reg = <0>;
                        };
                };
 
-               i2c@3d40 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d40 0x40>;
-                       interrupts = <2 16 0>;
+               ata@3a00 {
+                       status = "disabled";
                };
 
-               sram@8000 {
-                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
-                       reg = <0x8000 0x4000>;
+               i2c@3d00 {
+                       status = "disabled";
                };
+
        };
 
-       localbus {
-               compatible = "fsl,mpc5200b-lpb","simple-bus";
-               #address-cells = <2>;
-               #size-cells = <1>;
-               ranges = <0 0 0xfc000000 0x2000000>;
+       pci@f0000d00 {
+               status = "disabled";
+       };
 
+       localbus {
                // 16-bit flash device at LocalPlus Bus CS0
                flash@0,0 {
                        compatible = "cfi-flash";
index 8e9be6bfe23e46a40dd78072054536986a1b1785..27bd267d631cb58a42ebd7f149d8709e1e607755 100644 (file)
  * option) any later version.
  */
 
-/dts-v1/;
+/include/ "mpc5200b.dtsi"
 
 / {
        model = "intercontrol,digsy-mtc";
        compatible = "intercontrol,digsy-mtc";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       interrupt-parent = <&mpc5200_pic>;
-
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               PowerPC,5200@0 {
-                       device_type = "cpu";
-                       reg = <0>;
-                       d-cache-line-size = <32>;
-                       i-cache-line-size = <32>;
-                       d-cache-size = <0x4000>;                // L1, 16K
-                       i-cache-size = <0x4000>;                // L1, 16K
-                       timebase-frequency = <0>;       // from bootloader
-                       bus-frequency = <0>;            // from bootloader
-                       clock-frequency = <0>;          // from bootloader
-               };
-       };
 
        memory {
-               device_type = "memory";
                reg = <0x00000000 0x02000000>;  // 32MB
        };
 
        soc5200@f0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc5200b-immr";
-               ranges = <0 0xf0000000 0x0000c000>;
-               reg = <0xf0000000 0x00000100>;
-               bus-frequency = <0>;            // from bootloader
-               system-frequency = <0>;         // from bootloader
-
-               cdm@200 {
-                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
-                       reg = <0x200 0x38>;
-               };
-
-               mpc5200_pic: interrupt-controller@500 {
-                       // 5200 interrupts are encoded into two levels;
-                       interrupt-controller;
-                       #interrupt-cells = <3>;
-                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
-                       reg = <0x500 0x80>;
-               };
-
                timer@600 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x600 0x10>;
-                       interrupts = <1 9 0>;
                        fsl,has-wdt;
                };
 
-               timer@610 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x610 0x10>;
-                       interrupts = <1 10 0>;
-               };
-
-               timer@620 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x620 0x10>;
-                       interrupts = <1 11 0>;
-               };
-
-               timer@630 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x630 0x10>;
-                       interrupts = <1 12 0>;
-               };
-
-               timer@640 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x640 0x10>;
-                       interrupts = <1 13 0>;
-               };
-
-               timer@650 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x650 0x10>;
-                       interrupts = <1 14 0>;
+               rtc@800 {
+                       status = "disabled";
                };
 
-               timer@660 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x660 0x10>;
-                       interrupts = <1 15 0>;
+               can@900 {
+                       status = "disabled";
                };
 
-               timer@670 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x670 0x10>;
-                       interrupts = <1 16 0>;
+               can@980 {
+                       status = "disabled";
                };
 
-               gpio_simple: gpio@b00 {
-                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
-                       reg = <0xb00 0x40>;
-                       interrupts = <1 7 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
+               psc@2000 {              // PSC1
+                       status = "disabled";
                };
 
-               gpio_wkup: gpio@c00 {
-                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
-                       reg = <0xc00 0x40>;
-                       interrupts = <1 8 0 0 3 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
+               psc@2200 {              // PSC2
+                       status = "disabled";
                };
 
-               spi@f00 {
-                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-                       reg = <0xf00 0x20>;
-                       interrupts = <2 13 0 2 14 0>;
+               psc@2400 {              // PSC3
+                       status = "disabled";
                };
 
-               usb@1000 {
-                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
-                       reg = <0x1000 0xff>;
-                       interrupts = <2 6 0>;
-               };
-
-               dma-controller@1200 {
-                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
-                       reg = <0x1200 0x80>;
-                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
-                                     3 4 0  3 5 0  3 6 0  3 7 0
-                                     3 8 0  3 9 0  3 10 0  3 11 0
-                                     3 12 0  3 13 0  3 14 0  3 15 0>;
-               };
-
-               xlb@1f00 {
-                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
-                       reg = <0x1f00 0x100>;
+               psc@2600 {              // PSC4
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
                };
 
-               serial@2600 {           // PSC4
+               psc@2800 {              // PSC5
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2600 0x100>;
-                       interrupts = <2 11 0>;
                };
 
-               serial@2800 {           // PSC5
-                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2800 0x100>;
-                       interrupts = <2 12 0>;
+               psc@2c00 {              // PSC6
+                       status = "disabled";
                };
 
                ethernet@3000 {
-                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
-                       reg = <0x3000 0x400>;
-                       local-mac-address = [ 00 00 00 00 00 00 ];
-                       interrupts = <2 5 0>;
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
-                       reg = <0x3000 0x400>;       // fec range, since we need to setup fec interrupts
-                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-
                        phy0: ethernet-phy@0 {
                                reg = <0>;
                        };
                };
 
-               ata@3a00 {
-                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
-                       reg = <0x3a00 0x100>;
-                       interrupts = <2 7 0>;
-               };
-
                i2c@3d00 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d00 0x40>;
-                       interrupts = <2 15 0>;
-
                        rtc@50 {
                                compatible = "at,24c08";
                                reg = <0x50>;
                        };
                };
 
-               sram@8000 {
-                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
-                       reg = <0x8000 0x4000>;
+               i2c@3d40 {
+                       status = "disabled";
                };
        };
 
-       lpb {
-               compatible = "fsl,mpc5200b-lpb","simple-bus";
-               #address-cells = <2>;
-               #size-cells = <1>;
+       pci@f0000d00 {
+               status = "disabled";
+       };
+
+       localbus {
                ranges = <0 0 0xff000000 0x1000000>;
 
                // 16-bit flash device at LocalPlus Bus CS0
index cad9c3840afca0896ec248e8a74085305c79fd0c..71d3bb4931dc05cc3e70d801bd32071692357afd 100644 (file)
                        };
 
                        IIC: i2c@ef600500 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                compatible = "ibm,iic-405ep", "ibm,iic";
                                reg = <0xef600500 0x00000011>;
                                interrupt-parent = <&UIC0>;
index 59702ace900f9dc07a447e51fe34bb481b83864e..fb288bb882b6d7f4111c19b5f69b79c390382e05 100644 (file)
  * option) any later version.
  */
 
-/dts-v1/;
+/include/ "mpc5200b.dtsi"
 
 / {
        model = "fsl,lite5200b";
        compatible = "fsl,lite5200b";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       interrupt-parent = <&mpc5200_pic>;
-
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               PowerPC,5200@0 {
-                       device_type = "cpu";
-                       reg = <0>;
-                       d-cache-line-size = <32>;
-                       i-cache-line-size = <32>;
-                       d-cache-size = <0x4000>;        // L1, 16K
-                       i-cache-size = <0x4000>;        // L1, 16K
-                       timebase-frequency = <0>;       // from bootloader
-                       bus-frequency = <0>;            // from bootloader
-                       clock-frequency = <0>;          // from bootloader
-               };
-       };
 
        memory {
-               device_type = "memory";
                reg = <0x00000000 0x10000000>;  // 256MB
        };
 
        soc5200@f0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc5200b-immr";
-               ranges = <0 0xf0000000 0x0000c000>;
-               reg = <0xf0000000 0x00000100>;
-               bus-frequency = <0>;            // from bootloader
-               system-frequency = <0>;         // from bootloader
-
-               cdm@200 {
-                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
-                       reg = <0x200 0x38>;
-               };
-
-               mpc5200_pic: interrupt-controller@500 {
-                       // 5200 interrupts are encoded into two levels;
-                       interrupt-controller;
-                       #interrupt-cells = <3>;
-                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
-                       reg = <0x500 0x80>;
-               };
-
                timer@600 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x600 0x10>;
-                       interrupts = <1 9 0>;
                        fsl,has-wdt;
                };
 
-               timer@610 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x610 0x10>;
-                       interrupts = <1 10 0>;
-               };
-
-               timer@620 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x620 0x10>;
-                       interrupts = <1 11 0>;
-               };
-
-               timer@630 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x630 0x10>;
-                       interrupts = <1 12 0>;
-               };
-
-               timer@640 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x640 0x10>;
-                       interrupts = <1 13 0>;
-               };
-
-               timer@650 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x650 0x10>;
-                       interrupts = <1 14 0>;
-               };
-
-               timer@660 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x660 0x10>;
-                       interrupts = <1 15 0>;
-               };
-
-               timer@670 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x670 0x10>;
-                       interrupts = <1 16 0>;
-               };
-
-               rtc@800 {       // Real time clock
-                       compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
-                       reg = <0x800 0x100>;
-                       interrupts = <1 5 0 1 6 0>;
-               };
-
-               can@900 {
-                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       interrupts = <2 17 0>;
-                       reg = <0x900 0x80>;
-               };
-
-               can@980 {
-                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       interrupts = <2 18 0>;
-                       reg = <0x980 0x80>;
-               };
-
-               gpio_simple: gpio@b00 {
-                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
-                       reg = <0xb00 0x40>;
-                       interrupts = <1 7 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
-               };
-
-               gpio_wkup: gpio@c00 {
-                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
-                       reg = <0xc00 0x40>;
-                       interrupts = <1 8 0 0 3 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
+               psc@2000 {              // PSC1
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       cell-index = <0>;
                };
 
-               spi@f00 {
-                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-                       reg = <0xf00 0x20>;
-                       interrupts = <2 13 0 2 14 0>;
+               psc@2200 {              // PSC2
+                       status = "disabled";
                };
 
-               usb@1000 {
-                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
-                       reg = <0x1000 0xff>;
-                       interrupts = <2 6 0>;
+               psc@2400 {              // PSC3
+                       status = "disabled";
                };
 
-               dma-controller@1200 {
-                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
-                       reg = <0x1200 0x80>;
-                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
-                                     3 4 0  3 5 0  3 6 0  3 7 0
-                                     3 8 0  3 9 0  3 10 0  3 11 0
-                                     3 12 0  3 13 0  3 14 0  3 15 0>;
+               psc@2600 {              // PSC4
+                       status = "disabled";
                };
 
-               xlb@1f00 {
-                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
-                       reg = <0x1f00 0x100>;
+               psc@2800 {              // PSC5
+                       status = "disabled";
                };
 
-               serial@2000 {           // PSC1
-                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       cell-index = <0>;
-                       reg = <0x2000 0x100>;
-                       interrupts = <2 1 0>;
+               psc@2c00 {              // PSC6
+                       status = "disabled";
                };
 
                // PSC2 in ac97 mode example
                //ac97@2200 {           // PSC2
                //      compatible = "fsl,mpc5200b-psc-ac97","fsl,mpc5200-psc-ac97";
                //      cell-index = <1>;
-               //      reg = <0x2200 0x100>;
-               //      interrupts = <2 2 0>;
                //};
 
                // PSC3 in CODEC mode example
                //i2s@2400 {            // PSC3
                //      compatible = "fsl,mpc5200b-psc-i2s"; //not 5200 compatible
                //      cell-index = <2>;
-               //      reg = <0x2400 0x100>;
-               //      interrupts = <2 3 0>;
-               //};
-
-               // PSC4 in uart mode example
-               //serial@2600 {         // PSC4
-               //      compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-               //      cell-index = <3>;
-               //      reg = <0x2600 0x100>;
-               //      interrupts = <2 11 0>;
-               //};
-
-               // PSC5 in uart mode example
-               //serial@2800 {         // PSC5
-               //      compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-               //      cell-index = <4>;
-               //      reg = <0x2800 0x100>;
-               //      interrupts = <2 12 0>;
                //};
 
                // PSC6 in spi mode example
                //spi@2c00 {            // PSC6
                //      compatible = "fsl,mpc5200b-psc-spi","fsl,mpc5200-psc-spi";
                //      cell-index = <5>;
-               //      reg = <0x2c00 0x100>;
-               //      interrupts = <2 4 0>;
                //};
 
                ethernet@3000 {
-                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
-                       reg = <0x3000 0x400>;
-                       local-mac-address = [ 00 00 00 00 00 00 ];
-                       interrupts = <2 5 0>;
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
-                       reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
-                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-
                        phy0: ethernet-phy@0 {
                                reg = <0>;
                        };
                };
 
-               ata@3a00 {
-                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
-                       reg = <0x3a00 0x100>;
-                       interrupts = <2 7 0>;
-               };
-
-               i2c@3d00 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d00 0x40>;
-                       interrupts = <2 15 0>;
-               };
-
                i2c@3d40 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d40 0x40>;
-                       interrupts = <2 16 0>;
-
                        eeprom@50 {
                                compatible = "atmel,24c02";
                                reg = <0x50>;
        };
 
        pci@f0000d00 {
-               #interrupt-cells = <1>;
-               #size-cells = <2>;
-               #address-cells = <3>;
-               device_type = "pci";
-               compatible = "fsl,mpc5200b-pci","fsl,mpc5200-pci";
-               reg = <0xf0000d00 0x100>;
                interrupt-map-mask = <0xf800 0 0 7>;
                interrupt-map = <0xc000 0 0 1 &mpc5200_pic 0 0 3 // 1st slot
                                 0xc000 0 0 2 &mpc5200_pic 1 1 3
        };
 
        localbus {
-               compatible = "fsl,mpc5200b-lpb","fsl,mpc5200-lpb","simple-bus";
-
-               #address-cells = <2>;
-               #size-cells = <1>;
-
                ranges = <0 0 0xfe000000 0x02000000>;
 
                flash@0,0 {
index 0c3902bc5b6a148542316fe4d12f2b46d38743e1..48d72f38e5edd79daf2650cf21b67e3275b408f0 100644 (file)
  * option) any later version.
  */
 
-/dts-v1/;
+/include/ "mpc5200b.dtsi"
 
 / {
        model = "fsl,media5200";
        compatible = "fsl,media5200";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       interrupt-parent = <&mpc5200_pic>;
 
        aliases {
                console = &console;
        };
 
        cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
                PowerPC,5200@0 {
-                       device_type = "cpu";
-                       reg = <0>;
-                       d-cache-line-size = <32>;
-                       i-cache-line-size = <32>;
-                       d-cache-size = <0x4000>;                // L1, 16K
-                       i-cache-size = <0x4000>;                // L1, 16K
                        timebase-frequency = <33000000>;        // 33 MHz, these were configured by U-Boot
                        bus-frequency = <132000000>;            // 132 MHz
                        clock-frequency = <396000000>;          // 396 MHz
        };
 
        memory {
-               device_type = "memory";
                reg = <0x00000000 0x08000000>;  // 128MB RAM
        };
 
-       soc@f0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc5200b-immr";
-               ranges = <0 0xf0000000 0x0000c000>;
-               reg = <0xf0000000 0x00000100>;
+       soc5200@f0000000 {
                bus-frequency = <132000000>;// 132 MHz
-               system-frequency = <0>;         // from bootloader
-
-               cdm@200 {
-                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
-                       reg = <0x200 0x38>;
-               };
-
-               mpc5200_pic: interrupt-controller@500 {
-                       // 5200 interrupts are encoded into two levels;
-                       interrupt-controller;
-                       #interrupt-cells = <3>;
-                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
-                       reg = <0x500 0x80>;
-               };
 
                timer@600 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x600 0x10>;
-                       interrupts = <1 9 0>;
                        fsl,has-wdt;
                };
 
-               timer@610 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x610 0x10>;
-                       interrupts = <1 10 0>;
-               };
-
-               timer@620 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x620 0x10>;
-                       interrupts = <1 11 0>;
-               };
-
-               timer@630 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x630 0x10>;
-                       interrupts = <1 12 0>;
-               };
-
-               timer@640 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x640 0x10>;
-                       interrupts = <1 13 0>;
-               };
-
-               timer@650 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x650 0x10>;
-                       interrupts = <1 14 0>;
-               };
-
-               timer@660 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x660 0x10>;
-                       interrupts = <1 15 0>;
-               };
-
-               timer@670 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x670 0x10>;
-                       interrupts = <1 16 0>;
-               };
-
-               rtc@800 {       // Real time clock
-                       compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
-                       reg = <0x800 0x100>;
-                       interrupts = <1 5 0 1 6 0>;
-               };
-
-               can@900 {
-                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       interrupts = <2 17 0>;
-                       reg = <0x900 0x80>;
+               psc@2000 {      // PSC1
+                       status = "disabled";
                };
 
-               can@980 {
-                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       interrupts = <2 18 0>;
-                       reg = <0x980 0x80>;
+               psc@2200 {      // PSC2
+                       status = "disabled";
                };
 
-               gpio_simple: gpio@b00 {
-                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
-                       reg = <0xb00 0x40>;
-                       interrupts = <1 7 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
+               psc@2400 {      // PSC3
+                       status = "disabled";
                };
 
-               gpio_wkup: gpio@c00 {
-                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
-                       reg = <0xc00 0x40>;
-                       interrupts = <1 8 0 0 3 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
+               psc@2600 {      // PSC4
+                       status = "disabled";
                };
 
-               spi@f00 {
-                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-                       reg = <0xf00 0x20>;
-                       interrupts = <2 13 0 2 14 0>;
-               };
-
-               usb@1000 {
-                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
-                       reg = <0x1000 0x100>;
-                       interrupts = <2 6 0>;
-               };
-
-               dma-controller@1200 {
-                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
-                       reg = <0x1200 0x80>;
-                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
-                                     3 4 0  3 5 0  3 6 0  3 7 0
-                                     3 8 0  3 9 0  3 10 0  3 11 0
-                                     3 12 0  3 13 0  3 14 0  3 15 0>;
-               };
-
-               xlb@1f00 {
-                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
-                       reg = <0x1f00 0x100>;
+               psc@2800 {      // PSC5
+                       status = "disabled";
                };
 
                // PSC6 in uart mode
-               console: serial@2c00 {          // PSC6
+               console: psc@2c00 {             // PSC6
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       cell-index = <5>;
-                       port-number = <0>;  // Logical port assignment
-                       reg = <0x2c00 0x100>;
-                       interrupts = <2 4 0>;
                };
 
-               eth0: ethernet@3000 {
-                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
-                       reg = <0x3000 0x400>;
-                       local-mac-address = [ 00 00 00 00 00 00 ];
-                       interrupts = <2 5 0>;
+               ethernet@3000 {
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
-                       reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
-                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-
                        phy0: ethernet-phy@0 {
                                reg = <0>;
                        };
                };
 
-               ata@3a00 {
-                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
-                       reg = <0x3a00 0x100>;
-                       interrupts = <2 7 0>;
-               };
-
-               i2c@3d00 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d00 0x40>;
-                       interrupts = <2 15 0>;
-               };
-
-               i2c@3d40 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d40 0x40>;
-                       interrupts = <2 16 0>;
-               };
-
-               sram@8000 {
-                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
-                       reg = <0x8000 0x4000>;
+               usb@1000 {
+                       reg = <0x1000 0x100>;
                };
        };
 
        pci@f0000d00 {
-               #interrupt-cells = <1>;
-               #size-cells = <2>;
-               #address-cells = <3>;
-               device_type = "pci";
-               compatible = "fsl,mpc5200b-pci","fsl,mpc5200-pci";
-               reg = <0xf0000d00 0x100>;
                interrupt-map-mask = <0xf800 0 0 7>;
                interrupt-map = <0xc000 0 0 1 &media5200_fpga 0 2 // 1st slot
                                 0xc000 0 0 2 &media5200_fpga 0 3
 
                                 0xe000 0 0 1 &media5200_fpga 0 5 // CoralIP
                                >;
-               clock-frequency = <0>; // From boot loader
-               interrupts = <2 8 0 2 9 0 2 10 0>;
-               interrupt-parent = <&mpc5200_pic>;
-               bus-range = <0 0>;
                ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
                          0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
                          0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
+               interrupt-parent = <&mpc5200_pic>;
        };
 
        localbus {
-               compatible = "fsl,mpc5200b-lpb","simple-bus";
-               #address-cells = <2>;
-               #size-cells = <1>;
-
                ranges = < 0 0 0xfc000000 0x02000000
                           1 0 0xfe000000 0x02000000
                           2 0 0xf0010000 0x00010000
                           3 0 0xf0020000 0x00010000 >;
-
                flash@0,0 {
                        compatible = "amd,am29lv28ml", "cfi-flash";
-                       reg = <0 0x0 0x2000000>;                // 32 MB
-                       bank-width = <4>;                       // Width in bytes of the flash bank
-                       device-width = <2>;                     // Two devices on each bank
+                       reg = <0 0x0 0x2000000>;                // 32 MB
+                       bank-width = <4>;                       // Width in bytes of the flash bank
+                       device-width = <2>;                     // Two devices on each bank
                };
 
                flash@1,0 {
                        compatible = "amd,am29lv28ml", "cfi-flash";
-                       reg = <1 0 0x2000000>;                  // 32 MB
-                       bank-width = <4>;                       // Width in bytes of the flash bank
-                       device-width = <2>;                     // Two devices on each bank
+                       reg = <1 0 0x2000000>;                  // 32 MB
+                       bank-width = <4>;                       // Width in bytes of the flash bank
+                       device-width = <2>;                     // Two devices on each bank
                };
 
                media5200_fpga: fpga@2,0 {
index 6ca4fc144a33a6b4344c1ee02e70d6bdbf04a7d8..0b78e89ac69bedf2a9d7462ba22e47ba21a0e01d 100644 (file)
  * option) any later version.
  */
 
-/dts-v1/;
+/include/ "mpc5200b.dtsi"
 
 / {
        model = "promess,motionpro";
        compatible = "promess,motionpro";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       interrupt-parent = <&mpc5200_pic>;
-
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               PowerPC,5200@0 {
-                       device_type = "cpu";
-                       reg = <0>;
-                       d-cache-line-size = <32>;
-                       i-cache-line-size = <32>;
-                       d-cache-size = <0x4000>;        // L1, 16K
-                       i-cache-size = <0x4000>;        // L1, 16K
-                       timebase-frequency = <0>;       // from bootloader
-                       bus-frequency = <0>;            // from bootloader
-                       clock-frequency = <0>;          // from bootloader
-               };
-       };
-
-       memory {
-               device_type = "memory";
-               reg = <0x00000000 0x04000000>;  // 64MB
-       };
 
        soc5200@f0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc5200b-immr";
-               ranges = <0 0xf0000000 0x0000c000>;
-               reg = <0xf0000000 0x00000100>;
-               bus-frequency = <0>;            // from bootloader
-               system-frequency = <0>;         // from bootloader
-
-               cdm@200 {
-                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
-                       reg = <0x200 0x38>;
-               };
-
-               mpc5200_pic: interrupt-controller@500 {
-                       // 5200 interrupts are encoded into two levels;
-                       interrupt-controller;
-                       #interrupt-cells = <3>;
-                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
-                       reg = <0x500 0x80>;
-               };
-
                timer@600 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x600 0x10>;
-                       interrupts = <1 9 0>;
                        fsl,has-wdt;
                };
 
-               timer@610 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x610 0x10>;
-                       interrupts = <1 10 0>;
-               };
-
-               timer@620 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x620 0x10>;
-                       interrupts = <1 11 0>;
-               };
-
-               timer@630 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x630 0x10>;
-                       interrupts = <1 12 0>;
-               };
-
-               timer@640 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x640 0x10>;
-                       interrupts = <1 13 0>;
-               };
-
-               timer@650 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x650 0x10>;
-                       interrupts = <1 14 0>;
-               };
-
-               motionpro-led@660 {     // Motion-PRO status LED
+               timer@660 {     // Motion-PRO status LED
                        compatible = "promess,motionpro-led";
                        label = "motionpro-statusled";
-                       reg = <0x660 0x10>;
-                       interrupts = <1 15 0>;
                        blink-delay = <100>; // 100 msec
                };
 
-               motionpro-led@670 {     // Motion-PRO ready LED
+               timer@670 {     // Motion-PRO ready LED
                        compatible = "promess,motionpro-led";
                        label = "motionpro-readyled";
-                       reg = <0x670 0x10>;
-                       interrupts = <1 16 0>;
-               };
-
-               rtc@800 {       // Real time clock
-                       compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
-                       reg = <0x800 0x100>;
-                       interrupts = <1 5 0 1 6 0>;
-               };
-
-               can@980 {
-                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       interrupts = <2 18 0>;
-                       reg = <0x980 0x80>;
                };
 
-               gpio_simple: gpio@b00 {
-                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
-                       reg = <0xb00 0x40>;
-                       interrupts = <1 7 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
+               can@900 {
+                       status = "disabled";
                };
 
-               gpio_wkup: gpio@c00 {
-                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
-                       reg = <0xc00 0x40>;
-                       interrupts = <1 8 0 0 3 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
-               };
-
-               spi@f00 {
-                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-                       reg = <0xf00 0x20>;
-                       interrupts = <2 13 0 2 14 0>;
+               psc@2000 {              // PSC1
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
                };
 
-               usb@1000 {
-                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
-                       reg = <0x1000 0xff>;
-                       interrupts = <2 6 0>;
+               // PSC2 in spi master mode 
+               psc@2200 {              // PSC2
+                       compatible = "fsl,mpc5200b-psc-spi","fsl,mpc5200-psc-spi";
+                       cell-index = <1>;
                };
 
-               dma-controller@1200 {
-                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
-                       reg = <0x1200 0x80>;
-                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
-                                     3 4 0  3 5 0  3 6 0  3 7 0
-                                     3 8 0  3 9 0  3 10 0  3 11 0
-                                     3 12 0  3 13 0  3 14 0  3 15 0>;
+               psc@2400 {              // PSC3
+                       status = "disabled";
                };
 
-               xlb@1f00 {
-                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
-                       reg = <0x1f00 0x100>;
+               psc@2600 {              // PSC4
+                       status = "disabled";
                };
 
-               serial@2000 {           // PSC1
+               psc@2800 {              // PSC5
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2000 0x100>;
-                       interrupts = <2 1 0>;
-               };
-
-               // PSC2 in spi master mode 
-               spi@2200 {              // PSC2
-                       compatible = "fsl,mpc5200b-psc-spi","fsl,mpc5200-psc-spi";
-                       cell-index = <1>;
-                       reg = <0x2200 0x100>;
-                       interrupts = <2 2 0>;
                };
 
-               // PSC5 in uart mode
-               serial@2800 {           // PSC5
-                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2800 0x100>;
-                       interrupts = <2 12 0>;
+               psc@2c00 {              // PSC6
+                       status = "disabled";
                };
 
                ethernet@3000 {
-                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
-                       reg = <0x3000 0x400>;
-                       local-mac-address = [ 00 00 00 00 00 00 ];
-                       interrupts = <2 5 0>;
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
-                       reg = <0x3000 0x400>;       // fec range, since we need to setup fec interrupts
-                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-
                        phy0: ethernet-phy@2 {
                                reg = <2>;
                        };
                };
 
-               ata@3a00 {
-                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
-                       reg = <0x3a00 0x100>;
-                       interrupts = <2 7 0>;
+               i2c@3d00 {
+                       status = "disabled";
                };
 
                i2c@3d40 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d40 0x40>;
-                       interrupts = <2 16 0>;
-
                        rtc@68 {
                                compatible = "dallas,ds1339";
                                reg = <0x68>;
                };
        };
 
+       pci@f0000d00 {
+               status = "disabled";
+       };
+
        localbus {
-               compatible = "fsl,mpc5200b-lpb","simple-bus";
-               #address-cells = <2>;
-               #size-cells = <1>;
                ranges = <0 0 0xff000000 0x01000000
                          1 0 0x50000000 0x00010000
                          2 0 0x50010000 0x00010000
                        #size-cells = <1>;
                        #address-cells = <1>;
                };
+
        };
 };
diff --git a/arch/powerpc/boot/dts/mpc5200b.dtsi b/arch/powerpc/boot/dts/mpc5200b.dtsi
new file mode 100644 (file)
index 0000000..bc27548
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * base MPC5200b Device Tree Source
+ *
+ * Copyright (C) 2010 SecretLab
+ * Grant Likely <grant@secretlab.ca>
+ * John Bonesio <bones@secretlab.ca>
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+/ {
+       model = "fsl,mpc5200b";
+       compatible = "fsl,mpc5200b";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               powerpc: PowerPC,5200@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;
+                       i-cache-line-size = <32>;
+                       d-cache-size = <0x4000>;        // L1, 16K
+                       i-cache-size = <0x4000>;        // L1, 16K
+                       timebase-frequency = <0>;       // from bootloader
+                       bus-frequency = <0>;            // from bootloader
+                       clock-frequency = <0>;          // from bootloader
+               };
+       };
+
+       memory: memory {
+               device_type = "memory";
+               reg = <0x00000000 0x04000000>;  // 64MB
+       };
+
+       soc: soc5200@f0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc5200b-immr";
+               ranges = <0 0xf0000000 0x0000c000>;
+               reg = <0xf0000000 0x00000100>;
+               bus-frequency = <0>;            // from bootloader
+               system-frequency = <0>;         // from bootloader
+
+               cdm@200 {
+                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
+                       reg = <0x200 0x38>;
+               };
+
+               mpc5200_pic: interrupt-controller@500 {
+                       // 5200 interrupts are encoded into two levels;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
+                       reg = <0x500 0x80>;
+               };
+
+               timer@600 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x600 0x10>;
+                       interrupts = <1 9 0>;
+               };
+
+               timer@610 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x610 0x10>;
+                       interrupts = <1 10 0>;
+               };
+
+               timer@620 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x620 0x10>;
+                       interrupts = <1 11 0>;
+               };
+
+               timer@630 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x630 0x10>;
+                       interrupts = <1 12 0>;
+               };
+
+               timer@640 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x640 0x10>;
+                       interrupts = <1 13 0>;
+               };
+
+               timer@650 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x650 0x10>;
+                       interrupts = <1 14 0>;
+               };
+
+               timer@660 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x660 0x10>;
+                       interrupts = <1 15 0>;
+               };
+
+               timer@670 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+                       reg = <0x670 0x10>;
+                       interrupts = <1 16 0>;
+               };
+
+               rtc@800 {       // Real time clock
+                       compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
+                       reg = <0x800 0x100>;
+                       interrupts = <1 5 0 1 6 0>;
+               };
+
+               can@900 {
+                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
+                       interrupts = <2 17 0>;
+                       reg = <0x900 0x80>;
+               };
+
+               can@980 {
+                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
+                       interrupts = <2 18 0>;
+                       reg = <0x980 0x80>;
+               };
+
+               gpio_simple: gpio@b00 {
+                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
+                       reg = <0xb00 0x40>;
+                       interrupts = <1 7 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpio_wkup: gpio@c00 {
+                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
+                       reg = <0xc00 0x40>;
+                       interrupts = <1 8 0 0 3 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               spi@f00 {
+                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
+                       reg = <0xf00 0x20>;
+                       interrupts = <2 13 0 2 14 0>;
+               };
+
+               usb: usb@1000 {
+                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
+                       reg = <0x1000 0xff>;
+                       interrupts = <2 6 0>;
+               };
+
+               dma-controller@1200 {
+                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
+                       reg = <0x1200 0x80>;
+                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
+                                     3 4 0  3 5 0  3 6 0  3 7 0
+                                     3 8 0  3 9 0  3 10 0  3 11 0
+                                     3 12 0  3 13 0  3 14 0  3 15 0>;
+               };
+
+               xlb@1f00 {
+                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
+                       reg = <0x1f00 0x100>;
+               };
+
+               psc1: psc@2000 {                // PSC1
+                       compatible = "fsl,mpc5200b-psc","fsl,mpc5200-psc";
+                       reg = <0x2000 0x100>;
+                       interrupts = <2 1 0>;
+               };
+
+               psc2: psc@2200 {                // PSC2
+                       compatible = "fsl,mpc5200b-psc","fsl,mpc5200-psc";
+                       reg = <0x2200 0x100>;
+                       interrupts = <2 2 0>;
+               };
+
+               psc3: psc@2400 {                // PSC3
+                       compatible = "fsl,mpc5200b-psc","fsl,mpc5200-psc";
+                       reg = <0x2400 0x100>;
+                       interrupts = <2 3 0>;
+               };
+
+               psc4: psc@2600 {                // PSC4
+                       compatible = "fsl,mpc5200b-psc","fsl,mpc5200-psc";
+                       reg = <0x2600 0x100>;
+                       interrupts = <2 11 0>;
+               };
+
+               psc5: psc@2800 {                // PSC5
+                       compatible = "fsl,mpc5200b-psc","fsl,mpc5200-psc";
+                       reg = <0x2800 0x100>;
+                       interrupts = <2 12 0>;
+               };
+
+               psc6: psc@2c00 {                // PSC6
+                       compatible = "fsl,mpc5200b-psc","fsl,mpc5200-psc";
+                       reg = <0x2c00 0x100>;
+                       interrupts = <2 4 0>;
+               };
+
+               eth0: ethernet@3000 {
+                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
+                       reg = <0x3000 0x400>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <2 5 0>;
+               };
+
+               mdio@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
+                       reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
+                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
+               };
+
+               ata@3a00 {
+                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
+                       reg = <0x3a00 0x100>;
+                       interrupts = <2 7 0>;
+               };
+
+               i2c@3d00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+                       reg = <0x3d00 0x40>;
+                       interrupts = <2 15 0>;
+               };
+
+               i2c@3d40 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+                       reg = <0x3d40 0x40>;
+                       interrupts = <2 16 0>;
+               };
+
+               sram@8000 {
+                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
+                       reg = <0x8000 0x4000>;
+               };
+       };
+
+       pci: pci@f0000d00 {
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               device_type = "pci";
+               compatible = "fsl,mpc5200b-pci","fsl,mpc5200-pci";
+               reg = <0xf0000d00 0x100>;
+               // interrupt-map-mask = need to add
+               // interrupt-map = need to add
+               clock-frequency = <0>; // From boot loader
+               interrupts = <2 8 0 2 9 0 2 10 0>;
+               bus-range = <0 0>;
+               // ranges = need to add
+       };
+
+       localbus: localbus {
+               compatible = "fsl,mpc5200b-lpb","fsl,mpc5200-lpb","simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges = <0 0 0xfc000000 0x2000000>;
+       };
+};
index b72a7581d79858666c4a21b5eea67e438bddc3a5..21d34720fcc91f4f7f3dab73c44180b0795f167c 100644 (file)
  * option) any later version.
  */
 
-/dts-v1/;
+/include/ "mpc5200b.dtsi"
 
 / {
        model = "manroland,mucmc52";
        compatible = "manroland,mucmc52";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       interrupt-parent = <&mpc5200_pic>;
-
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               PowerPC,5200@0 {
-                       device_type = "cpu";
-                       reg = <0>;
-                       d-cache-line-size = <32>;
-                       i-cache-line-size = <32>;
-                       d-cache-size = <0x4000>;        // L1, 16K
-                       i-cache-size = <0x4000>;        // L1, 16K
-                       timebase-frequency = <0>;       // from bootloader
-                       bus-frequency = <0>;            // from bootloader
-                       clock-frequency = <0>;          // from bootloader
-               };
-       };
-
-       memory {
-               device_type = "memory";
-               reg = <0x00000000 0x04000000>;  // 64MB
-       };
 
        soc5200@f0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc5200b-immr";
-               ranges = <0 0xf0000000 0x0000c000>;
-               reg = <0xf0000000 0x00000100>;
-               bus-frequency = <0>;            // from bootloader
-               system-frequency = <0>;         // from bootloader
-
-               cdm@200 {
-                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
-                       reg = <0x200 0x38>;
-               };
-
-               mpc5200_pic: interrupt-controller@500 {
-                       // 5200 interrupts are encoded into two levels;
-                       interrupt-controller;
-                       #interrupt-cells = <3>;
-                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
-                       reg = <0x500 0x80>;
-               };
-
                gpt0: timer@600 {       // GPT 0 in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x600 0x10>;
-                       interrupts = <1 9 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt1: timer@610 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x610 0x10>;
-                       interrupts = <1 10 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt2: timer@620 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x620 0x10>;
-                       interrupts = <1 11 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt3: timer@630 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x630 0x10>;
-                       interrupts = <1 12 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
-               gpio_simple: gpio@b00 {
-                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
-                       reg = <0xb00 0x40>;
-                       interrupts = <1 7 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
+               timer@640 {
+                       status = "disabled";
                };
 
-               gpio_wkup: gpio@c00 {
-                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
-                       reg = <0xc00 0x40>;
-                       interrupts = <1 8 0 0 3 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
+               timer@650 {
+                       status = "disabled";
+               };
+
+               timer@660 {
+                       status = "disabled";
+               };
+
+               timer@670 {
+                       status = "disabled";
                };
 
-               dma-controller@1200 {
-                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
-                       reg = <0x1200 0x80>;
-                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
-                                     3 4 0  3 5 0  3 6 0  3 7 0
-                                     3 8 0  3 9 0  3 10 0  3 11 0
-                                     3 12 0  3 13 0  3 14 0  3 15 0>;
+               rtc@800 {
+                       status = "disabled";
                };
 
-               xlb@1f00 {
-                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
-                       reg = <0x1f00 0x100>;
+               can@900 {
+                       status = "disabled";
                };
 
-               serial@2000 { /* PSC1 in UART mode */
+               can@980 {
+                       status = "disabled";
+               };
+
+               spi@f00 {
+                       status = "disabled";
+               };
+
+               usb@1000 {
+                       status = "disabled";
+               };
+
+               psc@2000 {              // PSC1
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2000 0x100>;
-                       interrupts = <2 1 0>;
                };
 
-               serial@2200 { /* PSC2 in UART mode */
+               psc@2200 {              // PSC2
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2200 0x100>;
-                       interrupts = <2 2 0>;
                };
 
-               serial@2c00 { /* PSC6 in UART mode */
+               psc@2400 {              // PSC3
+                       status = "disabled";
+               };
+
+               psc@2600 {              // PSC4
+                       status = "disabled";
+               };
+
+               psc@2800 {              // PSC5
+                       status = "disabled";
+               };
+
+               psc@2c00 {              // PSC6
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2c00 0x100>;
-                       interrupts = <2 4 0>;
                };
 
                ethernet@3000 {
-                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
-                       reg = <0x3000 0x400>;
-                       local-mac-address = [ 00 00 00 00 00 00 ];
-                       interrupts = <2 5 0>;
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
-                       reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
-                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-
                        phy0: ethernet-phy@0 {
                                compatible = "intel,lxt971";
                                reg = <0>;
                        };
                };
 
-               ata@3a00 {
-                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
-                       reg = <0x3a00 0x100>;
-                       interrupts = <2 7 0>;
+               i2c@3d00 {
+                       status = "disabled";
                };
 
                i2c@3d40 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d40 0x40>;
-                       interrupts = <2 16 0>;
                        hwmon@2c {
                                compatible = "ad,adm9240";
                                reg = <0x2c>;
                                reg = <0x51>;
                        };
                };
-
-               sram@8000 {
-                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
-                       reg = <0x8000 0x4000>;
-               };
        };
 
        pci@f0000d00 {
-               #interrupt-cells = <1>;
-               #size-cells = <2>;
-               #address-cells = <3>;
-               device_type = "pci";
-               compatible = "fsl,mpc5200b-pci","fsl,mpc5200-pci";
-               reg = <0xf0000d00 0x100>;
                interrupt-map-mask = <0xf800 0 0 7>;
                interrupt-map = <
                                /* IDSEL 0x10 */
                                0x8000 0 0 3 &mpc5200_pic 0 2 3
                                0x8000 0 0 4 &mpc5200_pic 0 1 3
                                >;
-               clock-frequency = <0>; // From boot loader
-               interrupts = <2 8 0 2 9 0 2 10 0>;
-               bus-range = <0 0>;
                ranges = <0x42000000 0 0x60000000 0x60000000 0 0x10000000
                          0x02000000 0 0x90000000 0x90000000 0 0x10000000
                          0x01000000 0 0x00000000 0xa0000000 0 0x01000000>;
        };
 
        localbus {
-               compatible = "fsl,mpc5200b-lpb","fsl,mpc5200-lpb","simple-bus";
-
-               #address-cells = <2>;
-               #size-cells = <1>;
-
                ranges = <0 0 0xff800000 0x00800000
                          1 0 0x80000000 0x00800000
                          3 0 0x80000000 0x00800000>;
index 8a4ec30b21aeb3b6d55ee7eb5cb455399fae4ca4..9e354997eb7e3ccc29ac70ee5e7a31c3ce319b01 100644 (file)
  * option) any later version.
  */
 
-/dts-v1/;
+/include/ "mpc5200b.dtsi"
 
 / {
        model = "phytec,pcm030";
        compatible = "phytec,pcm030";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       interrupt-parent = <&mpc5200_pic>;
-
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               PowerPC,5200@0 {
-                       device_type = "cpu";
-                       reg = <0>;
-                       d-cache-line-size = <32>;
-                       i-cache-line-size = <32>;
-                       d-cache-size = <0x4000>;        // L1, 16K
-                       i-cache-size = <0x4000>;        // L1, 16K
-                       timebase-frequency = <0>;       // from bootloader
-                       bus-frequency = <0>;            // from bootloader
-                       clock-frequency = <0>;          // from bootloader
-               };
-       };
-
-       memory {
-               device_type = "memory";
-               reg = <0x00000000 0x04000000>;  // 64MB
-       };
 
        soc5200@f0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc5200b-immr";
-               ranges = <0 0xf0000000 0x0000c000>;
-               bus-frequency = <0>;            // from bootloader
-               system-frequency = <0>;         // from bootloader
-
-               cdm@200 {
-                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
-                       reg = <0x200 0x38>;
-               };
-
-               mpc5200_pic: interrupt-controller@500 {
-                       // 5200 interrupts are encoded into two levels;
-                       interrupt-controller;
-                       #interrupt-cells = <3>;
-                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
-                       reg = <0x500 0x80>;
-               };
-
-               timer@600 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x600 0x10>;
-                       interrupts = <1 9 0>;
+               timer@600 {             // General Purpose Timer
                        fsl,has-wdt;
                };
 
-               timer@610 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x610 0x10>;
-                       interrupts = <1 10 0>;
-               };
-
                gpt2: timer@620 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       reg = <0x620 0x10>;
-                       interrupts = <1 11 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt3: timer@630 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       reg = <0x630 0x10>;
-                       interrupts = <1 12 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt4: timer@640 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       reg = <0x640 0x10>;
-                       interrupts = <1 13 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt5: timer@650 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       reg = <0x650 0x10>;
-                       interrupts = <1 14 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt6: timer@660 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       reg = <0x660 0x10>;
-                       interrupts = <1 15 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt7: timer@670 {       // General Purpose Timer in GPIO mode
                        compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
-                       reg = <0x670 0x10>;
-                       interrupts = <1 16 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
-               };
-
-               rtc@800 {       // Real time clock
-                       compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
-                       reg = <0x800 0x100>;
-                       interrupts = <1 5 0 1 6 0>;
-               };
-
-               can@900 {
-                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       interrupts = <2 17 0>;
-                       reg = <0x900 0x80>;
-               };
-
-               can@980 {
-                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       interrupts = <2 18 0>;
-                       reg = <0x980 0x80>;
-               };
-
-               gpio_simple: gpio@b00 {
-                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
-                       reg = <0xb00 0x40>;
-                       interrupts = <1 7 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
-               gpio_wkup: gpio@c00 {
-                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
-                       reg = <0xc00 0x40>;
-                       interrupts = <1 8 0 0 3 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
-               };
-
-               spi@f00 {
-                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-                       reg = <0xf00 0x20>;
-                       interrupts = <2 13 0 2 14 0>;
-               };
-
-               usb@1000 {
-                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
-                       reg = <0x1000 0xff>;
-                       interrupts = <2 6 0>;
-               };
-
-               dma-controller@1200 {
-                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
-                       reg = <0x1200 0x80>;
-                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
-                                     3 4 0  3 5 0  3 6 0  3 7 0
-                                     3 8 0  3 9 0  3 10 0  3 11 0
-                                     3 12 0  3 13 0  3 14 0  3 15 0>;
-               };
-
-               xlb@1f00 {
-                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
-                       reg = <0x1f00 0x100>;
-               };
-
-               ac97@2000 { /* PSC1 in ac97 mode */
+               psc@2000 { /* PSC1 in ac97 mode */
                        compatible = "mpc5200b-psc-ac97","fsl,mpc5200b-psc-ac97";
                        cell-index = <0>;
-                       reg = <0x2000 0x100>;
-                       interrupts = <2 1 0>;
                };
 
                /* PSC2 port is used by CAN1/2 */
+               psc@2200 {
+                       status = "disabled";
+               };
 
-               serial@2400 { /* PSC3 in UART mode */
+               psc@2400 { /* PSC3 in UART mode */
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       cell-index = <2>;
-                       reg = <0x2400 0x100>;
-                       interrupts = <2 3 0>;
                };
 
                /* PSC4 is ??? */
+               psc@2600 {
+                       status = "disabled";
+               };
 
                /* PSC5 is ??? */
+               psc@2800 {
+                       status = "disabled";
+               };
 
-               serial@2c00 { /* PSC6 in UART mode */
+               psc@2c00 { /* PSC6 in UART mode */
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       cell-index = <5>;
-                       reg = <0x2c00 0x100>;
-                       interrupts = <2 4 0>;
                };
 
                ethernet@3000 {
-                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
-                       reg = <0x3000 0x400>;
-                       local-mac-address = [ 00 00 00 00 00 00 ];
-                       interrupts = <2 5 0>;
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
-                       reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
-                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-
                        phy0: ethernet-phy@0 {
                                reg = <0>;
                        };
                };
 
-               ata@3a00 {
-                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
-                       reg = <0x3a00 0x100>;
-                       interrupts = <2 7 0>;
-               };
-
-               i2c@3d00 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d00 0x40>;
-                       interrupts = <2 15 0>;
-               };
-
                i2c@3d40 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d40 0x40>;
-                       interrupts = <2 16 0>;
                        rtc@51 {
                                compatible = "nxp,pcf8563";
                                reg = <0x51>;
                        eeprom@52 {
                                compatible = "catalyst,24c32";
                                reg = <0x52>;
+                               pagesize = <32>;
                        };
                };
 
        };
 
        pci@f0000d00 {
-               #interrupt-cells = <1>;
-               #size-cells = <2>;
-               #address-cells = <3>;
-               device_type = "pci";
-               compatible = "fsl,mpc5200b-pci","fsl,mpc5200-pci";
-               reg = <0xf0000d00 0x100>;
                interrupt-map-mask = <0xf800 0 0 7>;
                interrupt-map = <0xc000 0 0 1 &mpc5200_pic 0 0 3 // 1st slot
                                 0xc000 0 0 2 &mpc5200_pic 1 1 3
                                 0xc800 0 0 2 &mpc5200_pic 1 2 3
                                 0xc800 0 0 3 &mpc5200_pic 1 3 3
                                 0xc800 0 0 4 &mpc5200_pic 0 0 3>;
-               clock-frequency = <0>; // From boot loader
-               interrupts = <2 8 0 2 9 0 2 10 0>;
-               bus-range = <0 0>;
                ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
                          0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
                          0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
        };
+
+       localbus {
+               status = "disabled";
+       };
 };
index 85d857a5d46e4f3a1409cb94f820028eccb0ddbb..1dd478bfff9636cabade5cecc00b8178442f3f61 100644 (file)
  * option) any later version.
  */
 
-/dts-v1/;
+/include/ "mpc5200b.dtsi"
 
 / {
        model = "phytec,pcm032";
        compatible = "phytec,pcm032";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       interrupt-parent = <&mpc5200_pic>;
-
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               PowerPC,5200@0 {
-                       device_type = "cpu";
-                       reg = <0>;
-                       d-cache-line-size = <32>;
-                       i-cache-line-size = <32>;
-                       d-cache-size = <0x4000>;        // L1, 16K
-                       i-cache-size = <0x4000>;        // L1, 16K
-                       timebase-frequency = <0>;       // from bootloader
-                       bus-frequency = <0>;            // from bootloader
-                       clock-frequency = <0>;          // from bootloader
-               };
-       };
 
        memory {
-               device_type = "memory";
                reg = <0x00000000 0x08000000>;  // 128MB
        };
 
        soc5200@f0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc5200b-immr";
-               ranges = <0 0xf0000000 0x0000c000>;
-               bus-frequency = <0>;            // from bootloader
-               system-frequency = <0>;         // from bootloader
-
-               cdm@200 {
-                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
-                       reg = <0x200 0x38>;
-               };
-
-               mpc5200_pic: interrupt-controller@500 {
-                       // 5200 interrupts are encoded into two levels;
-                       interrupt-controller;
-                       #interrupt-cells = <3>;
-                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
-                       reg = <0x500 0x80>;
-               };
-
-               timer@600 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x600 0x10>;
-                       interrupts = <1 9 0>;
+               timer@600 {             // General Purpose Timer
                        fsl,has-wdt;
                };
 
-               timer@610 {     // General Purpose Timer
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x610 0x10>;
-                       interrupts = <1 10 0>;
-               };
-
                gpt2: timer@620 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x620 0x10>;
-                       interrupts = <1 11 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt3: timer@630 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x630 0x10>;
-                       interrupts = <1 12 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt4: timer@640 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x640 0x10>;
-                       interrupts = <1 13 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt5: timer@650 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x650 0x10>;
-                       interrupts = <1 14 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
                };
 
                gpt7: timer@670 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x670 0x10>;
-                       interrupts = <1 16 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
-               rtc@800 {       // Real time clock
-                       compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
-                       reg = <0x800 0x100>;
-                       interrupts = <1 5 0 1 6 0>;
-               };
-
-               can@900 {
-                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       interrupts = <2 17 0>;
-                       reg = <0x900 0x80>;
-               };
-
-               can@980 {
-                       compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan";
-                       interrupts = <2 18 0>;
-                       reg = <0x980 0x80>;
-               };
-
-               gpio_simple: gpio@b00 {
-                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
-                       reg = <0xb00 0x40>;
-                       interrupts = <1 7 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
-               };
-
-               gpio_wkup: gpio@c00 {
-                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
-                       reg = <0xc00 0x40>;
-                       interrupts = <1 8 0 0 3 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
-               };
-
-               spi@f00 {
-                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-                       reg = <0xf00 0x20>;
-                       interrupts = <2 13 0 2 14 0>;
-               };
-
-               usb@1000 {
-                       compatible = "fsl,mpc5200b-ohci","fsl,mpc5200-ohci","ohci-be";
-                       reg = <0x1000 0xff>;
-                       interrupts = <2 6 0>;
-               };
-
-               dma-controller@1200 {
-                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
-                       reg = <0x1200 0x80>;
-                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
-                                     3 4 0  3 5 0  3 6 0  3 7 0
-                                     3 8 0  3 9 0  3 10 0  3 11 0
-                                     3 12 0  3 13 0  3 14 0  3 15 0>;
-               };
-
-               xlb@1f00 {
-                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
-                       reg = <0x1f00 0x100>;
-               };
-
-               ac97@2000 {     /* PSC1 is ac97 */
+               psc@2000 {      /* PSC1 is ac97 */
                        compatible = "fsl,mpc5200b-psc-ac97","fsl,mpc5200-psc-ac97";
                        cell-index = <0>;
-                       reg = <0x2000 0x100>;
-                       interrupts = <2 1 0>;
                };
 
                /* PSC2 port is used by CAN1/2 */
+               psc@2200 {
+                       status = "disabled";
+               };
 
-               serial@2400 { /* PSC3 in UART mode */
+               psc@2400 { /* PSC3 in UART mode */
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       cell-index = <2>;
-                       reg = <0x2400 0x100>;
-                       interrupts = <2 3 0>;
                };
 
                /* PSC4 is ??? */
+               psc@2600 {
+                       status = "disabled";
+               };
 
                /* PSC5 is ??? */
+               psc@2800 {
+                       status = "disabled";
+               };
 
-               serial@2c00 { /* PSC6 in UART mode */
+               psc@2c00 { /* PSC6 in UART mode */
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       cell-index = <5>;
-                       reg = <0x2c00 0x100>;
-                       interrupts = <2 4 0>;
                };
 
                ethernet@3000 {
-                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
-                       reg = <0x3000 0x400>;
-                       local-mac-address = [ 00 00 00 00 00 00 ];
-                       interrupts = <2 5 0>;
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
-                       reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
-                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-
                        phy0: ethernet-phy@0 {
                                reg = <0>;
                        };
                };
 
-               ata@3a00 {
-                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
-                       reg = <0x3a00 0x100>;
-                       interrupts = <2 7 0>;
-               };
-
-               i2c@3d00 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d00 0x40>;
-                       interrupts = <2 15 0>;
-               };
-
                i2c@3d40 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d40 0x40>;
-                       interrupts = <2 16 0>;
                        rtc@51 {
                                compatible = "nxp,pcf8563";
                                reg = <0x51>;
                        };
                        eeprom@52 {
-                               compatible = "at24,24c32";
+                               compatible = "catalyst,24c32";
                                reg = <0x52>;
+                               pagesize = <32>;
                        };
                };
-
-               sram@8000 {
-                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
-                       reg = <0x8000 0x4000>;
-               };
        };
 
        pci@f0000d00 {
-               #interrupt-cells = <1>;
-               #size-cells = <2>;
-               #address-cells = <3>;
-               device_type = "pci";
-               compatible = "fsl,mpc5200b-pci","fsl,mpc5200-pci";
-               reg = <0xf0000d00 0x100>;
                interrupt-map-mask = <0xf800 0 0 7>;
                interrupt-map = <0xc000 0 0 1 &mpc5200_pic 0 0 3 // 1st slot
                                 0xc000 0 0 2 &mpc5200_pic 1 1 3
                                 0xc800 0 0 2 &mpc5200_pic 1 2 3
                                 0xc800 0 0 3 &mpc5200_pic 1 3 3
                                 0xc800 0 0 4 &mpc5200_pic 0 0 3>;
-               clock-frequency = <0>; // From boot loader
-               interrupts = <2 8 0 2 9 0 2 10 0>;
-               bus-range = <0 0>;
                ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
                          0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
                          0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
        };
 
        localbus {
-               compatible = "fsl,mpc5200b-lpb","fsl,mpc5200-lpb","simple-bus";
-
-               #address-cells = <2>;
-               #size-cells = <1>;
-
                ranges = <0 0 0xfe000000 0x02000000
                          1 0 0xfc000000 0x02000000
                          2 0 0xfbe00000 0x00200000
                        bank-width = <2>;
                };
 
-                /*
+               /*
                 * example snippets for FPGA
                 *
                 * fpga@3,0 {
-                *         compatible = "fpga_driver";
-                *         reg = <3 0 0x02000000>;
-                *         bank-width = <4>;
+                *       compatible = "fpga_driver";
+                *       reg = <3 0 0x02000000>;
+                *       bank-width = <4>;
                 * };
                 *
                 * fpga@4,0 {
-                *         compatible = "fpga_driver";
-                *         reg = <4 0 0x02000000>;
-                *         bank-width = <4>;
+                *       compatible = "fpga_driver";
+                *       reg = <4 0 0x02000000>;
+                *       bank-width = <4>;
                 * };
-                 */
+                */
 
-                /*
+               /*
                 * example snippets for free chipselects
-                 *
+                *
                 * device@5,0 {
-                *         compatible = "custom_driver";
-                *         reg = <5 0 0x02000000>;
+                *       compatible = "custom_driver";
+                *       reg = <5 0 0x02000000>;
                 * };
-                 *
+                *
                 * device@6,0 {
-                *         compatible = "custom_driver";
-                *         reg = <6 0 0x02000000>;
+                *       compatible = "custom_driver";
+                *       reg = <6 0 0x02000000>;
                 * };
-                 *
+                *
                 * device@7,0 {
-                *         compatible = "custom_driver";
-                *         reg = <7 0 0x02000000>;
+                *       compatible = "custom_driver";
+                *       reg = <7 0 0x02000000>;
                 * };
-                 */
+                */
        };
 };
-
index 019264c62904fcc3b2d050fe3d1a37021326af66..ba83d5488ec6b83167df39640a80055ea29ea421 100644 (file)
  * option) any later version.
  */
 
-/dts-v1/;
+/include/ "mpc5200b.dtsi"
 
 / {
        model = "manroland,uc101";
        compatible = "manroland,uc101";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       interrupt-parent = <&mpc5200_pic>;
-
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               PowerPC,5200@0 {
-                       device_type = "cpu";
-                       reg = <0>;
-                       d-cache-line-size = <32>;
-                       i-cache-line-size = <32>;
-                       d-cache-size = <0x4000>;        // L1, 16K
-                       i-cache-size = <0x4000>;        // L1, 16K
-                       timebase-frequency = <0>;       // from bootloader
-                       bus-frequency = <0>;            // from bootloader
-                       clock-frequency = <0>;          // from bootloader
-               };
-       };
-
-       memory {
-               device_type = "memory";
-               reg = <0x00000000 0x04000000>;  // 64MB
-       };
 
        soc5200@f0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc5200b-immr";
-               ranges = <0 0xf0000000 0x0000c000>;
-               reg = <0xf0000000 0x00000100>;
-               bus-frequency = <0>;            // from bootloader
-               system-frequency = <0>;         // from bootloader
-
-               cdm@200 {
-                       compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
-                       reg = <0x200 0x38>;
-               };
-
-               mpc5200_pic: interrupt-controller@500 {
-                       // 5200 interrupts are encoded into two levels;
-                       interrupt-controller;
-                       #interrupt-cells = <3>;
-                       compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
-                       reg = <0x500 0x80>;
-               };
-
                gpt0: timer@600 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x600 0x10>;
-                       interrupts = <1 9 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt1: timer@610 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x610 0x10>;
-                       interrupts = <1 10 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt2: timer@620 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x620 0x10>;
-                       interrupts = <1 11 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
                };
 
                gpt4: timer@640 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x640 0x10>;
-                       interrupts = <1 13 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt5: timer@650 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x650 0x10>;
-                       interrupts = <1 14 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt6: timer@660 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x660 0x10>;
-                       interrupts = <1 15 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
                gpt7: timer@670 {       // General Purpose Timer in GPIO mode
-                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
-                       reg = <0x670 0x10>;
-                       interrupts = <1 16 0>;
                        gpio-controller;
                        #gpio-cells = <2>;
                };
 
-               gpio_simple: gpio@b00 {
-                       compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
-                       reg = <0xb00 0x40>;
-                       interrupts = <1 7 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
+               rtc@800 {
+                       status = "disabled";
                };
 
-               gpio_wkup: gpio@c00 {
-                       compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
-                       reg = <0xc00 0x40>;
-                       interrupts = <1 8 0 0 3 0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
+               can@900 {
+                       status = "disabled";
+               };
+
+               can@980 {
+                       status = "disabled";
                };
 
-               dma-controller@1200 {
-                       compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
-                       reg = <0x1200 0x80>;
-                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
-                                     3 4 0  3 5 0  3 6 0  3 7 0
-                                     3 8 0  3 9 0  3 10 0  3 11 0
-                                     3 12 0  3 13 0  3 14 0  3 15 0>;
+               spi@f00 {
+                       status = "disabled";
                };
 
-               xlb@1f00 {
-                       compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
-                       reg = <0x1f00 0x100>;
+               usb@1000 {
+                       status = "disabled";
                };
 
-               serial@2000 { /* PSC1 in UART mode */
+               psc@2000 {      // PSC1
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2000 0x100>;
-                       interrupts = <2 1 0>;
                };
 
-               serial@2200 { /* PSC2 in UART mode */
+               psc@2200 {      // PSC2
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2200 0x100>;
-                       interrupts = <2 2 0>;
                };
 
-               serial@2c00 {           /* PSC6 in UART mode */
+               psc@2400 {      // PSC3
+                       status = "disabled";
+               };
+
+               psc@2600 {      // PSC4
+                       status = "disabled";
+               };
+
+               psc@2800 {      // PSC5
+                       status = "disabled";
+               };
+
+               psc@2c00 {      // PSC6
                        compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
-                       reg = <0x2c00 0x100>;
-                       interrupts = <2 4 0>;
                };
 
                ethernet@3000 {
-                       compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
-                       reg = <0x3000 0x400>;
-                       local-mac-address = [ 00 00 00 00 00 00 ];
-                       interrupts = <2 5 0>;
                        phy-handle = <&phy0>;
                };
 
                mdio@3000 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
-                       reg = <0x3000 0x400>;   // fec range, since we need to setup fec interrupts
-                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
-
                        phy0: ethernet-phy@0 {
                                compatible = "intel,lxt971";
                                reg = <0>;
                        };
                };
 
-               ata@3a00 {
-                       compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
-                       reg = <0x3a00 0x100>;
-                       interrupts = <2 7 0>;
+               i2c@3d00 {
+                       status = "disabled";
                };
 
                i2c@3d40 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-                       reg = <0x3d40 0x40>;
-                       interrupts = <2 16 0>;
                        fsl,preserve-clocking;
                        clock-frequency = <400000>;
 
                                reg = <0x51>;
                        };
                };
+       };
 
-               sram@8000 {
-                       compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
-                       reg = <0x8000 0x4000>;
-               };
+       pci@f0000d00 {
+               status = "disabled";
        };
 
        localbus {
-               compatible = "fsl,mpc5200b-lpb","fsl,mpc5200-lpb","simple-bus";
-
-               #address-cells = <2>;
-               #size-cells = <1>;
-
                ranges = <0 0 0xff800000 0x00800000
                          1 0 0x80000000 0x00800000
                          3 0 0x80000000 0x00800000>;
index ae26f2efd089c80d92f0c9b50ea434dd43464f91..d72757585595d956ee5eb597432446d2b836477e 100644 (file)
@@ -42,7 +42,7 @@ extern void pci_create_OF_bus_map(void);
 
 /* Translate a DMA address from device space to CPU space */
 extern u64 of_translate_dma_address(struct device_node *dev,
-                                   const u32 *in_addr);
+                                   const __be32 *in_addr);
 
 #ifdef CONFIG_PCI
 extern unsigned long pci_address_to_pio(phys_addr_t address);
@@ -63,9 +63,6 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
 /* cache lookup */
 struct device_node *of_find_next_cache_node(struct device_node *np);
 
-/* Get the MAC address */
-extern const void *of_get_mac_address(struct device_node *np);
-
 #ifdef CONFIG_NUMA
 extern int of_node_to_nid(struct device_node *device);
 #else
index 88334af038e58453dc2fc8d5cbb12bad0fc175e9..c2b7a07cc3d3f54aeb22f7abe061c3ab6943708c 100644 (file)
@@ -117,41 +117,3 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
        cells = prop ? *(u32 *)prop : of_n_size_cells(dn);
        *size = of_read_number(dma_window, cells);
 }
-
-/**
- * Search the device tree for the best MAC address to use.  'mac-address' is
- * checked first, because that is supposed to contain to "most recent" MAC
- * address. If that isn't set, then 'local-mac-address' is checked next,
- * because that is the default address.  If that isn't set, then the obsolete
- * 'address' is checked, just in case we're using an old device tree.
- *
- * Note that the 'address' property is supposed to contain a virtual address of
- * the register set, but some DTS files have redefined that property to be the
- * MAC address.
- *
- * All-zero MAC addresses are rejected, because those could be properties that
- * exist in the device tree, but were not set by U-Boot.  For example, the
- * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
- * addresses.  Some older U-Boots only initialized 'local-mac-address'.  In
- * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
- * but is all zeros.
-*/
-const void *of_get_mac_address(struct device_node *np)
-{
-       struct property *pp;
-
-       pp = of_find_property(np, "mac-address", NULL);
-       if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
-               return pp->value;
-
-       pp = of_find_property(np, "local-mac-address", NULL);
-       if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
-               return pp->value;
-
-       pp = of_find_property(np, "address", NULL);
-       if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
-               return pp->value;
-
-       return NULL;
-}
-EXPORT_SYMBOL(of_get_mac_address);
index 546bbc229d19dd0d64277aa31b678f5b441eb432..2521d93ef136426d591820dd84995a84f349a27f 100644 (file)
@@ -50,7 +50,7 @@ machine_device_initcall(ppc40x_simple, ppc40x_device_probe);
  * Again, if your board needs to do things differently then create a
  * board.c file for it rather than adding it to this list.
  */
-static char *board[] __initdata = {
+static const char *board[] __initdata = {
        "amcc,acadia",
        "amcc,haleakala",
        "amcc,kilauea",
@@ -60,14 +60,9 @@ static char *board[] __initdata = {
 
 static int __init ppc40x_probe(void)
 {
-       unsigned long root = of_get_flat_dt_root();
-       int i = 0;
-
-       for (i = 0; i < ARRAY_SIZE(board); i++) {
-               if (of_flat_dt_is_compatible(root, board[i])) {
-                       ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC);
-                       return 1;
-               }
+       if (of_flat_dt_match(of_get_flat_dt_root(), board)) {
+               ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC);
+               return 1;
        }
 
        return 0;
index e487eb06ec6b294410a4650d0775556f8d448f11..926731f1ff01b587901cf88feab77161b4194849 100644 (file)
@@ -26,7 +26,7 @@
 /*
  * list of supported boards
  */
-static char *board[] __initdata = {
+static const char *board[] __initdata = {
        "prt,prtlvt",
        NULL
 };
@@ -36,16 +36,7 @@ static char *board[] __initdata = {
  */
 static int __init mpc5121_generic_probe(void)
 {
-       unsigned long node = of_get_flat_dt_root();
-       int i = 0;
-
-       while (board[i]) {
-               if (of_flat_dt_is_compatible(node, board[i]))
-                       break;
-               i++;
-       }
-
-       return board[i] != NULL;
+       return of_flat_dt_match(of_get_flat_dt_root(), board);
 }
 
 define_machine(mpc5121_generic) {
index de55bc0584b5d6cadaa24572db3302dbd0ea19ea..01ffa64d2aa7faf06582db473c96d4ac305621bd 100644 (file)
@@ -172,20 +172,18 @@ static void __init lite5200_setup_arch(void)
        mpc52xx_setup_pci();
 }
 
+static const char *board[] __initdata = {
+       "fsl,lite5200",
+       "fsl,lite5200b",
+       NULL,
+};
+
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
 static int __init lite5200_probe(void)
 {
-       unsigned long node = of_get_flat_dt_root();
-       const char *model = of_get_flat_dt_prop(node, "model", NULL);
-
-       if (!of_flat_dt_is_compatible(node, "fsl,lite5200") &&
-           !of_flat_dt_is_compatible(node, "fsl,lite5200b"))
-               return 0;
-       pr_debug("%s board found\n", model ? model : "unknown");
-
-       return 1;
+       return of_flat_dt_match(of_get_flat_dt_root(), board);
 }
 
 define_machine(lite5200) {
index 0bac3a3dbecfdf4fe189d897681ce388b584f508..2c7780cb68e598cff0e6817fb9a599a0ade7d821 100644 (file)
@@ -239,7 +239,7 @@ static void __init media5200_setup_arch(void)
 }
 
 /* list of the supported boards */
-static char *board[] __initdata = {
+static const char *board[] __initdata = {
        "fsl,media5200",
        NULL
 };
@@ -249,16 +249,7 @@ static char *board[] __initdata = {
  */
 static int __init media5200_probe(void)
 {
-       unsigned long node = of_get_flat_dt_root();
-       int i = 0;
-
-       while (board[i]) {
-               if (of_flat_dt_is_compatible(node, board[i]))
-                       break;
-               i++;
-       }
-
-       return (board[i] != NULL);
+       return of_flat_dt_match(of_get_flat_dt_root(), board);
 }
 
 define_machine(media5200_platform) {
index d45be5b5ad497baadb007821e479d7898879acab..e36d6e232ae66f4bf3033e5b60363cea25e46008 100644 (file)
@@ -49,7 +49,7 @@ static void __init mpc5200_simple_setup_arch(void)
 }
 
 /* list of the supported boards */
-static char *board[] __initdata = {
+static const char *board[] __initdata = {
        "intercontrol,digsy-mtc",
        "manroland,mucmc52",
        "manroland,uc101",
@@ -66,16 +66,7 @@ static char *board[] __initdata = {
  */
 static int __init mpc5200_simple_probe(void)
 {
-       unsigned long node = of_get_flat_dt_root();
-       int i = 0;
-
-       while (board[i]) {
-               if (of_flat_dt_is_compatible(node, board[i]))
-                       break;
-               i++;
-       }
-       
-       return (board[i] != NULL);
+       return of_flat_dt_match(of_get_flat_dt_root(), board);
 }
 
 define_machine(mpc5200_simple_platform) {
index 846831d495b57f6c1c9e123308ed9e3f2013848f..661d354e4ff27d15ee97aa18f663110177ab8ca4 100644 (file)
@@ -57,16 +57,19 @@ static void __init mpc830x_rdb_init_IRQ(void)
        ipic_set_default_priority();
 }
 
+struct const char *board[] __initdata = {
+       "MPC8308RDB",
+       "fsl,mpc8308rdb",
+       "denx,mpc8308_p1m",
+       NULL
+}
+
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
 static int __init mpc830x_rdb_probe(void)
 {
-       unsigned long root = of_get_flat_dt_root();
-
-       return of_flat_dt_is_compatible(root, "MPC8308RDB") ||
-              of_flat_dt_is_compatible(root, "fsl,mpc8308rdb") ||
-              of_flat_dt_is_compatible(root, "denx,mpc8308_p1m");
+       return of_flat_dt_match(of_get_flat_dt_root(), board);
 }
 
 static struct of_device_id __initdata of_bus_ids[] = {
index ae525e4745d2af9b3c4406f95458cadae6cf7382..b54cd736a895215250fea8c2c99159a9aa0965b7 100644 (file)
@@ -60,15 +60,18 @@ static void __init mpc831x_rdb_init_IRQ(void)
        ipic_set_default_priority();
 }
 
+struct const char *board[] __initdata = {
+       "MPC8313ERDB",
+       "fsl,mpc8315erdb",
+       NULL
+}
+
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
 static int __init mpc831x_rdb_probe(void)
 {
-       unsigned long root = of_get_flat_dt_root();
-
-       return of_flat_dt_is_compatible(root, "MPC8313ERDB") ||
-              of_flat_dt_is_compatible(root, "fsl,mpc8315erdb");
+       return of_flat_dt_match(of_get_flat_dt_root(), board);
 }
 
 static struct of_device_id __initdata of_bus_ids[] = {
index 910caa6b581056e7a4cb928a00998d2336f24818..7bafbf2ec0f92712aac0a1a259b22e1dd3de4b7f 100644 (file)
@@ -101,17 +101,20 @@ static void __init mpc837x_rdb_init_IRQ(void)
        ipic_set_default_priority();
 }
 
+static const char *board[] __initdata = {
+       "fsl,mpc8377rdb",
+       "fsl,mpc8378rdb",
+       "fsl,mpc8379rdb",
+       "fsl,mpc8377wlan",
+       NULL
+};
+
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
 static int __init mpc837x_rdb_probe(void)
 {
-       unsigned long root = of_get_flat_dt_root();
-
-       return of_flat_dt_is_compatible(root, "fsl,mpc8377rdb") ||
-              of_flat_dt_is_compatible(root, "fsl,mpc8378rdb") ||
-              of_flat_dt_is_compatible(root, "fsl,mpc8379rdb") ||
-              of_flat_dt_is_compatible(root, "fsl,mpc8377wlan");
+       return of_flat_dt_match(of_get_flat_dt_root(), board);
 }
 
 define_machine(mpc837x_rdb) {
index 8f29bbce5360447c3a719fb6b74877b417f35aed..5e847d0b47c80b5a63308e7e41a1ec4c8dce8917 100644 (file)
@@ -186,21 +186,21 @@ static int __init declare_of_platform_devices(void)
 }
 machine_device_initcall(tqm85xx, declare_of_platform_devices);
 
+static const char *board[] __initdata = {
+       "tqc,tqm8540",
+       "tqc,tqm8541",
+       "tqc,tqm8548",
+       "tqc,tqm8555",
+       "tqc,tqm8560",
+       NULL
+};
+
 /*
  * Called very early, device-tree isn't unflattened
  */
 static int __init tqm85xx_probe(void)
 {
-       unsigned long root = of_get_flat_dt_root();
-
-       if ((of_flat_dt_is_compatible(root, "tqc,tqm8540")) ||
-           (of_flat_dt_is_compatible(root, "tqc,tqm8541")) ||
-           (of_flat_dt_is_compatible(root, "tqc,tqm8548")) ||
-           (of_flat_dt_is_compatible(root, "tqc,tqm8555")) ||
-           (of_flat_dt_is_compatible(root, "tqc,tqm8560")))
-               return 1;
-
-       return 0;
+       return of_flat_dt_match(of_get_flat_dt_root(), board);
 }
 
 define_machine(tqm85xx) {
index 15e13b568904a4fb3eb7d533c3d4c0b650681d01..23982c7892d2a2abb470a74558a764f68045bca9 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/pci.h>
 #include <asm/ppc-pci.h>
 #include <asm/pci-bridge.h>
-#include <linux/kobject.h>
 
 /**
  * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic
index 1398bc454999b2b10fae54972e5e92c69689b3eb..feaee402e2d6ff6e43dbb9c4d9dd3c10b05c72d1 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/mv643xx.h>
 #include <linux/platform_device.h>
 #include <linux/of_platform.h>
+#include <linux/of_net.h>
 #include <linux/dma-mapping.h>
 
 #include <asm/prom.h>
index d4d15aaf18fabaeef8f13dc2f1b790b0c96458aa..c2d675b6392cb0b050eb82c16b74a46dd6aa4a90 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/of_net.h>
 #include <asm/tsi108.h>
 
 #include <asm/system.h>
index 7b42c247316c56e1e0fc85da723407c041f2097f..afc24556572bdc2863e6a022c1894a86ad8f92ff 100644 (file)
@@ -107,7 +107,7 @@ static int switch_drv_remove(struct platform_device *pdev)
                device_remove_file(&pdev->dev, &dev_attr_switch);
 
        platform_set_drvdata(pdev, NULL);
-       flush_scheduled_work();
+       flush_work_sync(&psw->work);
        del_timer_sync(&psw->debounce);
        free_irq(irq, pdev);
 
index 35f48837871aaf8bb185eea89aab0ba1e281910b..8505e0ac78baaf27331681302961f1bb7e173154 100644 (file)
@@ -121,7 +121,7 @@ void __init auxio_power_probe(void)
        node = prom_searchsiblings(node, "obio");
        node = prom_getchild(node);
        node = prom_searchsiblings(node, "power");
-       if (node == 0 || node == -1)
+       if (node == 0 || (s32)node == -1)
                return;
 
        /* Map the power control register. */
index a4446c0fb7a1c7220084c035f804e34d084c7a48..82281a566bb86b866525a18b8fc4ca453d2e1e60 100644 (file)
@@ -24,7 +24,7 @@ int this_is_starfire = 0;
 void check_if_starfire(void)
 {
        phandle ssnode = prom_finddevice("/ssp-serial");
-       if (ssnode != 0 && ssnode != -1)
+       if (ssnode != 0 && (s32)ssnode != -1)
                this_is_starfire = 1;
 }
 
index d342dba4dd54bb2c33f4a0804f383c2b34e3bc61..0a601b300639ff6ce7a0909c7b3a2ff544dbd8c3 100644 (file)
@@ -60,7 +60,7 @@ void __init prom_init(struct linux_romvec *rp)
        prom_nodeops = romvec->pv_nodeops;
 
        prom_root_node = prom_getsibling(0);
-       if((prom_root_node == 0) || (prom_root_node == -1))
+       if ((prom_root_node == 0) || ((s32)prom_root_node == -1))
                prom_halt();
 
        if((((unsigned long) prom_nodeops) == 0) || 
index 9c6ac4b81ded60922791cfa522c8fac1de04b151..5016c5e20575eb93ac0852714a271a67952a79b0 100644 (file)
@@ -35,13 +35,13 @@ void __init prom_init(void *cif_handler, void *cif_stack)
        prom_cif_init(cif_handler, cif_stack);
 
        prom_chosen_node = prom_finddevice(prom_chosen_path);
-       if (!prom_chosen_node || prom_chosen_node == -1)
+       if (!prom_chosen_node || (s32)prom_chosen_node == -1)
                prom_halt();
 
        prom_stdout = prom_getint(prom_chosen_node, "stdout");
 
        node = prom_finddevice("/openprom");
-       if (!node || node == -1)
+       if (!node || (s32)node == -1)
                prom_halt();
 
        prom_getstring(node, "version", prom_version, sizeof(prom_version));
index bc8e4cb87a683e8ebb643df4c52bfd335a5cbf3d..f30e8d038f01f7c4cb803a65e09b5a8c9ff3bda3 100644 (file)
@@ -40,11 +40,11 @@ phandle prom_getchild(phandle node)
 {
        phandle cnode;
 
-       if (node == -1)
+       if ((s32)node == -1)
                return 0;
 
        cnode = __prom_getchild(node);
-       if (cnode == 0 || cnode == -1)
+       if (cnode == 0 || (s32)cnode == -1)
                return 0;
 
        return cnode;
@@ -72,11 +72,11 @@ phandle prom_getsibling(phandle node)
 {
        phandle sibnode;
 
-       if (node == -1)
+       if ((s32)node == -1)
                return 0;
 
        sibnode = __prom_getsibling(node);
-       if (sibnode == 0 || sibnode == -1)
+       if (sibnode == 0 || (s32)sibnode == -1)
                return 0;
 
        return sibnode;
@@ -219,7 +219,7 @@ static char *__prom_nextprop(phandle node, char * oprop)
  */
 char *prom_nextprop(phandle node, char *oprop, char *buffer)
 {
-       if (node == 0 || node == -1)
+       if (node == 0 || (s32)node == -1)
                return "";
 
        return __prom_nextprop(node, oprop);
@@ -253,7 +253,7 @@ phandle prom_finddevice(char *name)
                                if (d != s + 3 && (!*d || *d == '/')
                                    && d <= s + 3 + 8) {
                                        node2 = node;
-                                       while (node2 && node2 != -1) {
+                                       while (node2 && (s32)node2 != -1) {
                                                if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) {
                                                        if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) {
                                                                node = node2;
@@ -261,7 +261,7 @@ phandle prom_finddevice(char *name)
                                                        }
                                                }
                                                node2 = prom_getsibling(node2);
-                                               if (!node2 || node2 == -1)
+                                               if (!node2 || (s32)node2 == -1)
                                                        break;
                                                node2 = prom_searchsiblings(prom_getsibling(node2), nbuf);
                                        }
@@ -303,6 +303,7 @@ phandle prom_inst2pkg(int inst)
        node = (*romvec->pv_v2devops.v2_inst2pkg)(inst);
        restore_current();
        spin_unlock_irqrestore(&prom_lock, flags);
-       if (node == -1) return 0;
+       if ((s32)node == -1)
+               return 0;
        return node;
 }
index d93660048376c9d9bf4478720a6825e9e7b117ed..92204c3800b57afe3366ffa49121001323c06243 100644 (file)
@@ -43,10 +43,10 @@ inline phandle prom_getchild(phandle node)
 {
        phandle cnode;
 
-       if (node == -1)
+       if ((s32)node == -1)
                return 0;
        cnode = __prom_getchild(node);
-       if (cnode == -1)
+       if ((s32)cnode == -1)
                return 0;
        return cnode;
 }
@@ -56,10 +56,10 @@ inline phandle prom_getparent(phandle node)
 {
        phandle cnode;
 
-       if (node == -1)
+       if ((s32)node == -1)
                return 0;
        cnode = prom_node_to_node("parent", node);
-       if (cnode == -1)
+       if ((s32)cnode == -1)
                return 0;
        return cnode;
 }
@@ -76,10 +76,10 @@ inline phandle prom_getsibling(phandle node)
 {
        phandle sibnode;
 
-       if (node == -1)
+       if ((s32)node == -1)
                return 0;
        sibnode = __prom_getsibling(node);
-       if (sibnode == -1)
+       if ((s32)sibnode == -1)
                return 0;
 
        return sibnode;
@@ -240,7 +240,7 @@ inline char *prom_firstprop(phandle node, char *buffer)
        unsigned long args[7];
 
        *buffer = 0;
-       if (node == -1)
+       if ((s32)node == -1)
                return buffer;
 
        args[0] = (unsigned long) prom_nextprop_name;
@@ -266,7 +266,7 @@ inline char *prom_nextprop(phandle node, const char *oprop, char *buffer)
        unsigned long args[7];
        char buf[32];
 
-       if (node == -1) {
+       if ((s32)node == -1) {
                *buffer = 0;
                return buffer;
        }
@@ -369,7 +369,7 @@ inline phandle prom_inst2pkg(int inst)
        p1275_cmd_direct(args);
 
        node = (int) args[4];
-       if (node == -1)
+       if ((s32)node == -1)
                return 0;
        return node;
 }
index 2ac9069890cdf594610e19424c54626bb1f051aa..15588a0ef4663054dc33d623e373f8edce90432a 100644 (file)
@@ -310,6 +310,9 @@ config X86_INTERNODE_CACHE_SHIFT
 config X86_CMPXCHG
        def_bool X86_64 || (X86_32 && !M386)
 
+config CMPXCHG_LOCAL
+       def_bool X86_64 || (X86_32 && !M386)
+
 config X86_L1_CACHE_SHIFT
        int
        default "7" if MPENTIUM4 || MPSC
index b81002f23614bb9ef6d9b75502f8ab08e228bc0d..078ad0caefc6115612d8ee60f8ba7da122346516 100644 (file)
@@ -94,7 +94,7 @@ static inline void hw_breakpoint_disable(void)
 
 static inline int hw_breakpoint_active(void)
 {
-       return __get_cpu_var(cpu_dr7) & DR_GLOBAL_ENABLE_MASK;
+       return __this_cpu_read(cpu_dr7) & DR_GLOBAL_ENABLE_MASK;
 }
 
 extern void aout_dump_debugregs(struct user *dump);
index ff2546ce7178e83e105ca9eadc9ddfcc71b636cf..7a15153c675ddc1a87c4e736bbd472a008cf5789 100644 (file)
@@ -20,6 +20,9 @@
 #ifndef _ASM_X86_HYPERVISOR_H
 #define _ASM_X86_HYPERVISOR_H
 
+#include <asm/kvm_para.h>
+#include <asm/xen/hypervisor.h>
+
 extern void init_hypervisor(struct cpuinfo_x86 *c);
 extern void init_hypervisor_platform(void);
 
@@ -47,4 +50,13 @@ extern const struct hypervisor_x86 x86_hyper_vmware;
 extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
 extern const struct hypervisor_x86 x86_hyper_xen_hvm;
 
+static inline bool hypervisor_x2apic_available(void)
+{
+       if (kvm_para_available())
+               return true;
+       if (xen_x2apic_para_available())
+               return true;
+       return false;
+}
+
 #endif
index f899e01a8ac965d0dfb90b8e8d0b1bda0d2fe812..8ee45167e8176d4a73814732428fad90f76c2966 100644 (file)
@@ -229,6 +229,125 @@ do {                                                                      \
        }                                               \
 })
 
+/*
+ * Add return operation
+ */
+#define percpu_add_return_op(var, val)                                 \
+({                                                                     \
+       typeof(var) paro_ret__ = val;                                   \
+       switch (sizeof(var)) {                                          \
+       case 1:                                                         \
+               asm("xaddb %0, "__percpu_arg(1)                         \
+                           : "+q" (paro_ret__), "+m" (var)             \
+                           : : "memory");                              \
+               break;                                                  \
+       case 2:                                                         \
+               asm("xaddw %0, "__percpu_arg(1)                         \
+                           : "+r" (paro_ret__), "+m" (var)             \
+                           : : "memory");                              \
+               break;                                                  \
+       case 4:                                                         \
+               asm("xaddl %0, "__percpu_arg(1)                         \
+                           : "+r" (paro_ret__), "+m" (var)             \
+                           : : "memory");                              \
+               break;                                                  \
+       case 8:                                                         \
+               asm("xaddq %0, "__percpu_arg(1)                         \
+                           : "+re" (paro_ret__), "+m" (var)            \
+                           : : "memory");                              \
+               break;                                                  \
+       default: __bad_percpu_size();                                   \
+       }                                                               \
+       paro_ret__ += val;                                              \
+       paro_ret__;                                                     \
+})
+
+/*
+ * xchg is implemented using cmpxchg without a lock prefix. xchg is
+ * expensive due to the implied lock prefix.  The processor cannot prefetch
+ * cachelines if xchg is used.
+ */
+#define percpu_xchg_op(var, nval)                                      \
+({                                                                     \
+       typeof(var) pxo_ret__;                                          \
+       typeof(var) pxo_new__ = (nval);                                 \
+       switch (sizeof(var)) {                                          \
+       case 1:                                                         \
+               asm("\n1:mov "__percpu_arg(1)",%%al"                    \
+                   "\n\tcmpxchgb %2, "__percpu_arg(1)                  \
+                   "\n\tjnz 1b"                                        \
+                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "q" (pxo_new__)                           \
+                           : "memory");                                \
+               break;                                                  \
+       case 2:                                                         \
+               asm("\n1:mov "__percpu_arg(1)",%%ax"                    \
+                   "\n\tcmpxchgw %2, "__percpu_arg(1)                  \
+                   "\n\tjnz 1b"                                        \
+                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "r" (pxo_new__)                           \
+                           : "memory");                                \
+               break;                                                  \
+       case 4:                                                         \
+               asm("\n1:mov "__percpu_arg(1)",%%eax"                   \
+                   "\n\tcmpxchgl %2, "__percpu_arg(1)                  \
+                   "\n\tjnz 1b"                                        \
+                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "r" (pxo_new__)                           \
+                           : "memory");                                \
+               break;                                                  \
+       case 8:                                                         \
+               asm("\n1:mov "__percpu_arg(1)",%%rax"                   \
+                   "\n\tcmpxchgq %2, "__percpu_arg(1)                  \
+                   "\n\tjnz 1b"                                        \
+                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "r" (pxo_new__)                           \
+                           : "memory");                                \
+               break;                                                  \
+       default: __bad_percpu_size();                                   \
+       }                                                               \
+       pxo_ret__;                                                      \
+})
+
+/*
+ * cmpxchg has no such implied lock semantics as a result it is much
+ * more efficient for cpu local operations.
+ */
+#define percpu_cmpxchg_op(var, oval, nval)                             \
+({                                                                     \
+       typeof(var) pco_ret__;                                          \
+       typeof(var) pco_old__ = (oval);                                 \
+       typeof(var) pco_new__ = (nval);                                 \
+       switch (sizeof(var)) {                                          \
+       case 1:                                                         \
+               asm("cmpxchgb %2, "__percpu_arg(1)                      \
+                           : "=a" (pco_ret__), "+m" (var)              \
+                           : "q" (pco_new__), "0" (pco_old__)          \
+                           : "memory");                                \
+               break;                                                  \
+       case 2:                                                         \
+               asm("cmpxchgw %2, "__percpu_arg(1)                      \
+                           : "=a" (pco_ret__), "+m" (var)              \
+                           : "r" (pco_new__), "0" (pco_old__)          \
+                           : "memory");                                \
+               break;                                                  \
+       case 4:                                                         \
+               asm("cmpxchgl %2, "__percpu_arg(1)                      \
+                           : "=a" (pco_ret__), "+m" (var)              \
+                           : "r" (pco_new__), "0" (pco_old__)          \
+                           : "memory");                                \
+               break;                                                  \
+       case 8:                                                         \
+               asm("cmpxchgq %2, "__percpu_arg(1)                      \
+                           : "=a" (pco_ret__), "+m" (var)              \
+                           : "r" (pco_new__), "0" (pco_old__)          \
+                           : "memory");                                \
+               break;                                                  \
+       default: __bad_percpu_size();                                   \
+       }                                                               \
+       pco_ret__;                                                      \
+})
+
 /*
  * percpu_read() makes gcc load the percpu variable every time it is
  * accessed while percpu_read_stable() allows the value to be cached.
@@ -267,6 +386,12 @@ do {                                                                       \
 #define __this_cpu_xor_1(pcp, val)     percpu_to_op("xor", (pcp), val)
 #define __this_cpu_xor_2(pcp, val)     percpu_to_op("xor", (pcp), val)
 #define __this_cpu_xor_4(pcp, val)     percpu_to_op("xor", (pcp), val)
+/*
+ * Generic fallback operations for __this_cpu_xchg_[1-4] are okay and much
+ * faster than an xchg with forced lock semantics.
+ */
+#define __this_cpu_xchg_8(pcp, nval)   percpu_xchg_op(pcp, nval)
+#define __this_cpu_cmpxchg_8(pcp, oval, nval)  percpu_cmpxchg_op(pcp, oval, nval)
 
 #define this_cpu_read_1(pcp)           percpu_from_op("mov", (pcp), "m"(pcp))
 #define this_cpu_read_2(pcp)           percpu_from_op("mov", (pcp), "m"(pcp))
@@ -286,6 +411,11 @@ do {                                                                       \
 #define this_cpu_xor_1(pcp, val)       percpu_to_op("xor", (pcp), val)
 #define this_cpu_xor_2(pcp, val)       percpu_to_op("xor", (pcp), val)
 #define this_cpu_xor_4(pcp, val)       percpu_to_op("xor", (pcp), val)
+#define this_cpu_xchg_1(pcp, nval)     percpu_xchg_op(pcp, nval)
+#define this_cpu_xchg_2(pcp, nval)     percpu_xchg_op(pcp, nval)
+#define this_cpu_xchg_4(pcp, nval)     percpu_xchg_op(pcp, nval)
+#define this_cpu_xchg_8(pcp, nval)     percpu_xchg_op(pcp, nval)
+#define this_cpu_cmpxchg_8(pcp, oval, nval)    percpu_cmpxchg_op(pcp, oval, nval)
 
 #define irqsafe_cpu_add_1(pcp, val)    percpu_add_op((pcp), val)
 #define irqsafe_cpu_add_2(pcp, val)    percpu_add_op((pcp), val)
@@ -299,6 +429,31 @@ do {                                                                       \
 #define irqsafe_cpu_xor_1(pcp, val)    percpu_to_op("xor", (pcp), val)
 #define irqsafe_cpu_xor_2(pcp, val)    percpu_to_op("xor", (pcp), val)
 #define irqsafe_cpu_xor_4(pcp, val)    percpu_to_op("xor", (pcp), val)
+#define irqsafe_cpu_xchg_1(pcp, nval)  percpu_xchg_op(pcp, nval)
+#define irqsafe_cpu_xchg_2(pcp, nval)  percpu_xchg_op(pcp, nval)
+#define irqsafe_cpu_xchg_4(pcp, nval)  percpu_xchg_op(pcp, nval)
+#define irqsafe_cpu_xchg_8(pcp, nval)  percpu_xchg_op(pcp, nval)
+#define irqsafe_cpu_cmpxchg_8(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
+
+#ifndef CONFIG_M386
+#define __this_cpu_add_return_1(pcp, val) percpu_add_return_op(pcp, val)
+#define __this_cpu_add_return_2(pcp, val) percpu_add_return_op(pcp, val)
+#define __this_cpu_add_return_4(pcp, val) percpu_add_return_op(pcp, val)
+#define __this_cpu_cmpxchg_1(pcp, oval, nval)  percpu_cmpxchg_op(pcp, oval, nval)
+#define __this_cpu_cmpxchg_2(pcp, oval, nval)  percpu_cmpxchg_op(pcp, oval, nval)
+#define __this_cpu_cmpxchg_4(pcp, oval, nval)  percpu_cmpxchg_op(pcp, oval, nval)
+
+#define this_cpu_add_return_1(pcp, val)        percpu_add_return_op(pcp, val)
+#define this_cpu_add_return_2(pcp, val)        percpu_add_return_op(pcp, val)
+#define this_cpu_add_return_4(pcp, val)        percpu_add_return_op(pcp, val)
+#define this_cpu_cmpxchg_1(pcp, oval, nval)    percpu_cmpxchg_op(pcp, oval, nval)
+#define this_cpu_cmpxchg_2(pcp, oval, nval)    percpu_cmpxchg_op(pcp, oval, nval)
+#define this_cpu_cmpxchg_4(pcp, oval, nval)    percpu_cmpxchg_op(pcp, oval, nval)
+
+#define irqsafe_cpu_cmpxchg_1(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_2(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_4(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
+#endif /* !CONFIG_M386 */
 
 /*
  * Per cpu atomic 64 bit operations are only available under 64 bit.
@@ -311,6 +466,7 @@ do {                                                                        \
 #define __this_cpu_and_8(pcp, val)     percpu_to_op("and", (pcp), val)
 #define __this_cpu_or_8(pcp, val)      percpu_to_op("or", (pcp), val)
 #define __this_cpu_xor_8(pcp, val)     percpu_to_op("xor", (pcp), val)
+#define __this_cpu_add_return_8(pcp, val) percpu_add_return_op(pcp, val)
 
 #define this_cpu_read_8(pcp)           percpu_from_op("mov", (pcp), "m"(pcp))
 #define this_cpu_write_8(pcp, val)     percpu_to_op("mov", (pcp), val)
@@ -318,12 +474,12 @@ do {                                                                      \
 #define this_cpu_and_8(pcp, val)       percpu_to_op("and", (pcp), val)
 #define this_cpu_or_8(pcp, val)                percpu_to_op("or", (pcp), val)
 #define this_cpu_xor_8(pcp, val)       percpu_to_op("xor", (pcp), val)
+#define this_cpu_add_return_8(pcp, val)        percpu_add_return_op(pcp, val)
 
 #define irqsafe_cpu_add_8(pcp, val)    percpu_add_op((pcp), val)
 #define irqsafe_cpu_and_8(pcp, val)    percpu_to_op("and", (pcp), val)
 #define irqsafe_cpu_or_8(pcp, val)     percpu_to_op("or", (pcp), val)
 #define irqsafe_cpu_xor_8(pcp, val)    percpu_to_op("xor", (pcp), val)
-
 #endif
 
 /* This is not atomic against other CPUs -- CPU preemption needs to be off */
index cae9c3cb95cf160e4e00f8c0b1c29fac298bb48f..c6efecf85a6a4b750805e3528e7d6b6c80dc22b7 100644 (file)
@@ -141,10 +141,9 @@ extern __u32                       cpu_caps_set[NCAPINTS];
 #ifdef CONFIG_SMP
 DECLARE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
 #define cpu_data(cpu)          per_cpu(cpu_info, cpu)
-#define current_cpu_data       __get_cpu_var(cpu_info)
 #else
+#define cpu_info               boot_cpu_data
 #define cpu_data(cpu)          boot_cpu_data
-#define current_cpu_data       boot_cpu_data
 #endif
 
 extern const struct seq_operations cpuinfo_op;
index 396ff4cc8ed480b7bc306f63091b88f6dda00442..66d0fff1ee8481ce0669cd5b0a137dde5d7dff8d 100644 (file)
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
 
+#include <asm/processor.h>
+
+static inline uint32_t xen_cpuid_base(void)
+{
+       uint32_t base, eax, ebx, ecx, edx;
+       char signature[13];
+
+       for (base = 0x40000000; base < 0x40010000; base += 0x100) {
+               cpuid(base, &eax, &ebx, &ecx, &edx);
+               *(uint32_t *)(signature + 0) = ebx;
+               *(uint32_t *)(signature + 4) = ecx;
+               *(uint32_t *)(signature + 8) = edx;
+               signature[12] = 0;
+
+               if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
+                       return base;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_XEN
+extern bool xen_hvm_need_lapic(void);
+
+static inline bool xen_x2apic_para_available(void)
+{
+       return xen_hvm_need_lapic();
+}
+#else
+static inline bool xen_x2apic_para_available(void)
+{
+       return (xen_cpuid_base() != 0);
+}
+#endif
+
 #endif /* _ASM_X86_XEN_HYPERVISOR_H */
index ce65d449b750f9dd3caa787d1df2e0211d5db3a8..a51345ba449e90a280e8fa1cdce90755abba4c26 100644 (file)
@@ -49,8 +49,8 @@
 #include <asm/mtrr.h>
 #include <asm/smp.h>
 #include <asm/mce.h>
-#include <asm/kvm_para.h>
 #include <asm/tsc.h>
+#include <asm/hypervisor.h>
 
 unsigned int num_processors;
 
@@ -516,7 +516,7 @@ static void __cpuinit setup_APIC_timer(void)
 {
        struct clock_event_device *levt = &__get_cpu_var(lapic_events);
 
-       if (cpu_has(&current_cpu_data, X86_FEATURE_ARAT)) {
+       if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_ARAT)) {
                lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP;
                /* Make LAPIC timer preferrable over percpu HPET */
                lapic_clockevent.rating = 150;
@@ -1476,7 +1476,8 @@ void __init enable_IR_x2apic(void)
                /* IR is required if there is APIC ID > 255 even when running
                 * under KVM
                 */
-               if (max_physical_apicid > 255 || !kvm_para_available())
+               if (max_physical_apicid > 255 ||
+                   !hypervisor_x2apic_available())
                        goto nox2apic;
                /*
                 * without IR all CPUs can be addressed by IOAPIC/MSI
index 52735a710c30db466d3a84c3e650e08725f24c42..697dc34b7b87611443ccdd06d39c8188f77ca94d 100644 (file)
@@ -2329,7 +2329,7 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
                unsigned int irr;
                struct irq_desc *desc;
                struct irq_cfg *cfg;
-               irq = __get_cpu_var(vector_irq)[vector];
+               irq = __this_cpu_read(vector_irq[vector]);
 
                if (irq == -1)
                        continue;
@@ -2363,7 +2363,7 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
                        apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);
                        goto unlock;
                }
-               __get_cpu_var(vector_irq)[vector] = -1;
+               __this_cpu_write(vector_irq[vector], -1);
 unlock:
                raw_spin_unlock(&desc->lock);
        }
index 2a3f2a7db243f8b846ef5d3032287037d0111a69..ecca5f41ad2c8f00c5a88f113451e1a5ed480ed7 100644 (file)
@@ -120,8 +120,8 @@ static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
                else if (!strcmp(oem_table_id, "UVX"))
                        uv_system_type = UV_X2APIC;
                else if (!strcmp(oem_table_id, "UVH")) {
-                       __get_cpu_var(x2apic_extra_bits) =
-                               pnodeid << uvh_apicid.s.pnode_shift;
+                       __this_cpu_write(x2apic_extra_bits,
+                               pnodeid << uvh_apicid.s.pnode_shift);
                        uv_system_type = UV_NON_UNIQUE_APIC;
                        uv_set_apicid_hibit();
                        return 1;
@@ -286,7 +286,7 @@ static unsigned int x2apic_get_apic_id(unsigned long x)
        unsigned int id;
 
        WARN_ON(preemptible() && num_online_cpus() > 1);
-       id = x | __get_cpu_var(x2apic_extra_bits);
+       id = x | __this_cpu_read(x2apic_extra_bits);
 
        return id;
 }
@@ -378,7 +378,7 @@ struct apic __refdata apic_x2apic_uv_x = {
 
 static __cpuinit void set_x2apic_extra_bits(int pnode)
 {
-       __get_cpu_var(x2apic_extra_bits) = (pnode << 6);
+       __this_cpu_write(x2apic_extra_bits, (pnode << 6));
 }
 
 /*
index 9e093f8fe78c4713aec4f91a62394eb0efa1f6c0..7c7bedb83c5a463bad2a2cd59765d3d6b1066f8b 100644 (file)
@@ -668,7 +668,7 @@ EXPORT_SYMBOL_GPL(amd_erratum_383);
 
 bool cpu_has_amd_erratum(const int *erratum)
 {
-       struct cpuinfo_x86 *cpu = &current_cpu_data;
+       struct cpuinfo_x86 *cpu = __this_cpu_ptr(&cpu_info);
        int osvw_id = *erratum++;
        u32 range;
        u32 ms;
index 491977baf6c0c5f374d988842f890fca183c7770..35c7e65e59be4b27e9242843184dd63af0ee8ed8 100644 (file)
@@ -521,7 +521,7 @@ static void check_supported_cpu(void *_rc)
 
        *rc = -ENODEV;
 
-       if (current_cpu_data.x86_vendor != X86_VENDOR_AMD)
+       if (__this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_AMD)
                return;
 
        eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
@@ -1377,7 +1377,7 @@ static int __devexit powernowk8_cpu_exit(struct cpufreq_policy *pol)
 static void query_values_on_cpu(void *_err)
 {
        int *err = _err;
-       struct powernow_k8_data *data = __get_cpu_var(powernow_data);
+       struct powernow_k8_data *data = __this_cpu_read(powernow_data);
 
        *err = query_current_values_with_pending_wait(data);
 }
index 9ecf81f9b90fb0c73416d958b1aa216b17e1ecfa..7283e98deaae14ca8f712acf3759f11cf7e9fc2b 100644 (file)
@@ -265,7 +265,7 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
                line_size = l2.line_size;
                lines_per_tag = l2.lines_per_tag;
                /* cpu_data has errata corrections for K7 applied */
-               size_in_kb = current_cpu_data.x86_cache_size;
+               size_in_kb = __this_cpu_read(cpu_info.x86_cache_size);
                break;
        case 3:
                if (!l3.val)
@@ -287,7 +287,7 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
        eax->split.type = types[leaf];
        eax->split.level = levels[leaf];
        eax->split.num_threads_sharing = 0;
-       eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
+       eax->split.num_cores_on_die = __this_cpu_read(cpu_info.x86_max_cores) - 1;
 
 
        if (assoc == 0xffff)
index 7a35b72d7c039d633bd8a4c9179eb4e4a5b7a549..d916183b7f9cfa77e9a6ae45531c44c38d4e563b 100644 (file)
@@ -326,7 +326,7 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
 
 static int msr_to_offset(u32 msr)
 {
-       unsigned bank = __get_cpu_var(injectm.bank);
+       unsigned bank = __this_cpu_read(injectm.bank);
 
        if (msr == rip_msr)
                return offsetof(struct mce, ip);
@@ -346,7 +346,7 @@ static u64 mce_rdmsrl(u32 msr)
 {
        u64 v;
 
-       if (__get_cpu_var(injectm).finished) {
+       if (__this_cpu_read(injectm.finished)) {
                int offset = msr_to_offset(msr);
 
                if (offset < 0)
@@ -369,7 +369,7 @@ static u64 mce_rdmsrl(u32 msr)
 
 static void mce_wrmsrl(u32 msr, u64 v)
 {
-       if (__get_cpu_var(injectm).finished) {
+       if (__this_cpu_read(injectm.finished)) {
                int offset = msr_to_offset(msr);
 
                if (offset >= 0)
@@ -1159,7 +1159,7 @@ static void mce_start_timer(unsigned long data)
 
        WARN_ON(smp_processor_id() != data);
 
-       if (mce_available(&current_cpu_data)) {
+       if (mce_available(__this_cpu_ptr(&cpu_info))) {
                machine_check_poll(MCP_TIMESTAMP,
                                &__get_cpu_var(mce_poll_banks));
        }
@@ -1767,7 +1767,7 @@ static int mce_shutdown(struct sys_device *dev)
 static int mce_resume(struct sys_device *dev)
 {
        __mcheck_cpu_init_generic();
-       __mcheck_cpu_init_vendor(&current_cpu_data);
+       __mcheck_cpu_init_vendor(__this_cpu_ptr(&cpu_info));
 
        return 0;
 }
@@ -1775,7 +1775,7 @@ static int mce_resume(struct sys_device *dev)
 static void mce_cpu_restart(void *data)
 {
        del_timer_sync(&__get_cpu_var(mce_timer));
-       if (!mce_available(&current_cpu_data))
+       if (!mce_available(__this_cpu_ptr(&cpu_info)))
                return;
        __mcheck_cpu_init_generic();
        __mcheck_cpu_init_timer();
@@ -1790,7 +1790,7 @@ static void mce_restart(void)
 /* Toggle features for corrected errors */
 static void mce_disable_ce(void *all)
 {
-       if (!mce_available(&current_cpu_data))
+       if (!mce_available(__this_cpu_ptr(&cpu_info)))
                return;
        if (all)
                del_timer_sync(&__get_cpu_var(mce_timer));
@@ -1799,7 +1799,7 @@ static void mce_disable_ce(void *all)
 
 static void mce_enable_ce(void *all)
 {
-       if (!mce_available(&current_cpu_data))
+       if (!mce_available(__this_cpu_ptr(&cpu_info)))
                return;
        cmci_reenable();
        cmci_recheck();
@@ -2022,7 +2022,7 @@ static void __cpuinit mce_disable_cpu(void *h)
        unsigned long action = *(unsigned long *)h;
        int i;
 
-       if (!mce_available(&current_cpu_data))
+       if (!mce_available(__this_cpu_ptr(&cpu_info)))
                return;
 
        if (!(action & CPU_TASKS_FROZEN))
@@ -2040,7 +2040,7 @@ static void __cpuinit mce_reenable_cpu(void *h)
        unsigned long action = *(unsigned long *)h;
        int i;
 
-       if (!mce_available(&current_cpu_data))
+       if (!mce_available(__this_cpu_ptr(&cpu_info)))
                return;
 
        if (!(action & CPU_TASKS_FROZEN))
index 6fcd0936194ff195cd78b14cdce76b997dd45ec9..8694ef56459d8e26761e6344df513ebf3af9dce6 100644 (file)
@@ -130,7 +130,7 @@ void cmci_recheck(void)
        unsigned long flags;
        int banks;
 
-       if (!mce_available(&current_cpu_data) || !cmci_supported(&banks))
+       if (!mce_available(__this_cpu_ptr(&cpu_info)) || !cmci_supported(&banks))
                return;
        local_irq_save(flags);
        machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned));
index 0a360d146596b6d01f8c833e655150faa3ae9605..04921017abe04fd748eae0acb73ce0d5866496e9 100644 (file)
@@ -997,8 +997,7 @@ x86_perf_event_set_period(struct perf_event *event)
 
 static void x86_pmu_enable_event(struct perf_event *event)
 {
-       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-       if (cpuc->enabled)
+       if (__this_cpu_read(cpu_hw_events.enabled))
                __x86_pmu_enable_event(&event->hw,
                                       ARCH_PERFMON_EVENTSEL_ENABLE);
 }
@@ -1272,7 +1271,7 @@ perf_event_nmi_handler(struct notifier_block *self,
                break;
        case DIE_NMIUNKNOWN:
                this_nmi = percpu_read(irq_stat.__nmi_count);
-               if (this_nmi != __get_cpu_var(pmu_nmi).marked)
+               if (this_nmi != __this_cpu_read(pmu_nmi.marked))
                        /* let the kernel handle the unknown nmi */
                        return NOTIFY_DONE;
                /*
@@ -1296,8 +1295,8 @@ perf_event_nmi_handler(struct notifier_block *self,
        this_nmi = percpu_read(irq_stat.__nmi_count);
        if ((handled > 1) ||
                /* the next nmi could be a back-to-back nmi */
-           ((__get_cpu_var(pmu_nmi).marked == this_nmi) &&
-            (__get_cpu_var(pmu_nmi).handled > 1))) {
+           ((__this_cpu_read(pmu_nmi.marked) == this_nmi) &&
+            (__this_cpu_read(pmu_nmi.handled) > 1))) {
                /*
                 * We could have two subsequent back-to-back nmis: The
                 * first handles more than one counter, the 2nd
@@ -1308,8 +1307,8 @@ perf_event_nmi_handler(struct notifier_block *self,
                 * handling more than one counter. We will mark the
                 * next (3rd) and then drop it if unhandled.
                 */
-               __get_cpu_var(pmu_nmi).marked   = this_nmi + 1;
-               __get_cpu_var(pmu_nmi).handled  = handled;
+               __this_cpu_write(pmu_nmi.marked, this_nmi + 1);
+               __this_cpu_write(pmu_nmi.handled, handled);
        }
 
        return NOTIFY_STOP;
@@ -1484,11 +1483,9 @@ static inline void x86_pmu_read(struct perf_event *event)
  */
 static void x86_pmu_start_txn(struct pmu *pmu)
 {
-       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-
        perf_pmu_disable(pmu);
-       cpuc->group_flag |= PERF_EVENT_TXN;
-       cpuc->n_txn = 0;
+       __this_cpu_or(cpu_hw_events.group_flag, PERF_EVENT_TXN);
+       __this_cpu_write(cpu_hw_events.n_txn, 0);
 }
 
 /*
@@ -1498,14 +1495,12 @@ static void x86_pmu_start_txn(struct pmu *pmu)
  */
 static void x86_pmu_cancel_txn(struct pmu *pmu)
 {
-       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-
-       cpuc->group_flag &= ~PERF_EVENT_TXN;
+       __this_cpu_and(cpu_hw_events.group_flag, ~PERF_EVENT_TXN);
        /*
         * Truncate the collected events.
         */
-       cpuc->n_added -= cpuc->n_txn;
-       cpuc->n_events -= cpuc->n_txn;
+       __this_cpu_sub(cpu_hw_events.n_added, __this_cpu_read(cpu_hw_events.n_txn));
+       __this_cpu_sub(cpu_hw_events.n_events, __this_cpu_read(cpu_hw_events.n_txn));
        perf_pmu_enable(pmu);
 }
 
index 24e390e40f2e0b484d4b2b09084deb9d120d59b4..008835c1d79ca2c5fb83b2c2ca2ddfeab657cca1 100644 (file)
@@ -649,7 +649,7 @@ static void intel_pmu_enable_event(struct perf_event *event)
        struct hw_perf_event *hwc = &event->hw;
 
        if (unlikely(hwc->idx == X86_PMC_IDX_FIXED_BTS)) {
-               if (!__get_cpu_var(cpu_hw_events).enabled)
+               if (!__this_cpu_read(cpu_hw_events.enabled))
                        return;
 
                intel_pmu_enable_bts(hwc->config);
@@ -679,7 +679,7 @@ static int intel_pmu_save_and_restart(struct perf_event *event)
 
 static void intel_pmu_reset(void)
 {
-       struct debug_store *ds = __get_cpu_var(cpu_hw_events).ds;
+       struct debug_store *ds = __this_cpu_read(cpu_hw_events.ds);
        unsigned long flags;
        int idx;
 
index 298448656b6079d074232518cb16e50895b4a5b8..382eb2936d4d57f40db5cb360efb8c7421cdc0cf 100644 (file)
@@ -170,9 +170,9 @@ static void ftrace_mod_code(void)
 
 void ftrace_nmi_enter(void)
 {
-       __get_cpu_var(save_modifying_code) = modifying_code;
+       __this_cpu_write(save_modifying_code, modifying_code);
 
-       if (!__get_cpu_var(save_modifying_code))
+       if (!__this_cpu_read(save_modifying_code))
                return;
 
        if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) {
@@ -186,7 +186,7 @@ void ftrace_nmi_enter(void)
 
 void ftrace_nmi_exit(void)
 {
-       if (!__get_cpu_var(save_modifying_code))
+       if (!__this_cpu_read(save_modifying_code))
                return;
 
        /* Finish all executions before clearing nmi_running */
index 42c59425450727284615b2a920611e21047ce715..02f07634d265ea0a840892b5bafbd554197644b8 100644 (file)
@@ -122,7 +122,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
                return -EBUSY;
 
        set_debugreg(info->address, i);
-       __get_cpu_var(cpu_debugreg[i]) = info->address;
+       __this_cpu_write(cpu_debugreg[i], info->address);
 
        dr7 = &__get_cpu_var(cpu_dr7);
        *dr7 |= encode_dr7(i, info->len, info->type);
@@ -397,12 +397,12 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
 
 void hw_breakpoint_restore(void)
 {
-       set_debugreg(__get_cpu_var(cpu_debugreg[0]), 0);
-       set_debugreg(__get_cpu_var(cpu_debugreg[1]), 1);
-       set_debugreg(__get_cpu_var(cpu_debugreg[2]), 2);
-       set_debugreg(__get_cpu_var(cpu_debugreg[3]), 3);
+       set_debugreg(__this_cpu_read(cpu_debugreg[0]), 0);
+       set_debugreg(__this_cpu_read(cpu_debugreg[1]), 1);
+       set_debugreg(__this_cpu_read(cpu_debugreg[2]), 2);
+       set_debugreg(__this_cpu_read(cpu_debugreg[3]), 3);
        set_debugreg(current->thread.debugreg6, 6);
-       set_debugreg(__get_cpu_var(cpu_dr7), 7);
+       set_debugreg(__this_cpu_read(cpu_dr7), 7);
 }
 EXPORT_SYMBOL_GPL(hw_breakpoint_restore);
 
index 83ec0175f986a5742c2ef85eff69d24100cd44b6..3a43caa3beb79a30e478d200c302d35187424cb4 100644 (file)
@@ -234,7 +234,7 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
        exit_idle();
        irq_enter();
 
-       irq = __get_cpu_var(vector_irq)[vector];
+       irq = __this_cpu_read(vector_irq[vector]);
 
        if (!handle_irq(irq, regs)) {
                ack_APIC_irq();
@@ -350,12 +350,12 @@ void fixup_irqs(void)
        for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
                unsigned int irr;
 
-               if (__get_cpu_var(vector_irq)[vector] < 0)
+               if (__this_cpu_read(vector_irq[vector]) < 0)
                        continue;
 
                irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
                if (irr  & (1 << (vector % 32))) {
-                       irq = __get_cpu_var(vector_irq)[vector];
+                       irq = __this_cpu_read(vector_irq[vector]);
 
                        data = irq_get_irq_data(irq);
                        raw_spin_lock(&desc->lock);
index 96656f2077511bf280eec0010a087c96649fdaaa..48ff6dcffa02774d4921331011dbcf6fe9070bc3 100644 (file)
@@ -79,7 +79,7 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
        u32 *isp, arg1, arg2;
 
        curctx = (union irq_ctx *) current_thread_info();
-       irqctx = __get_cpu_var(hardirq_ctx);
+       irqctx = __this_cpu_read(hardirq_ctx);
 
        /*
         * this is where we switch to the IRQ stack. However, if we are
@@ -166,7 +166,7 @@ asmlinkage void do_softirq(void)
 
        if (local_softirq_pending()) {
                curctx = current_thread_info();
-               irqctx = __get_cpu_var(softirq_ctx);
+               irqctx = __this_cpu_read(softirq_ctx);
                irqctx->tinfo.task = curctx->task;
                irqctx->tinfo.previous_esp = current_stack_pointer;
 
index 5940282bd2f94ed886226bc717c189e593adab50..d91c477b3f6234cf122a08cda38b8d9a571a27cf 100644 (file)
@@ -403,7 +403,7 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
 
 static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
 {
-       __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
+       __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
        kcb->kprobe_status = kcb->prev_kprobe.status;
        kcb->kprobe_old_flags = kcb->prev_kprobe.old_flags;
        kcb->kprobe_saved_flags = kcb->prev_kprobe.saved_flags;
@@ -412,7 +412,7 @@ static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
 static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
                                struct kprobe_ctlblk *kcb)
 {
-       __get_cpu_var(current_kprobe) = p;
+       __this_cpu_write(current_kprobe, p);
        kcb->kprobe_saved_flags = kcb->kprobe_old_flags
                = (regs->flags & (X86_EFLAGS_TF | X86_EFLAGS_IF));
        if (is_IF_modifier(p->ainsn.insn))
@@ -586,7 +586,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
                preempt_enable_no_resched();
                return 1;
        } else if (kprobe_running()) {
-               p = __get_cpu_var(current_kprobe);
+               p = __this_cpu_read(current_kprobe);
                if (p->break_handler && p->break_handler(p, regs)) {
                        setup_singlestep(p, regs, kcb, 0);
                        return 1;
@@ -759,11 +759,11 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
 
                orig_ret_address = (unsigned long)ri->ret_addr;
                if (ri->rp && ri->rp->handler) {
-                       __get_cpu_var(current_kprobe) = &ri->rp->kp;
+                       __this_cpu_write(current_kprobe, &ri->rp->kp);
                        get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
                        ri->ret_addr = correct_ret_addr;
                        ri->rp->handler(ri, regs);
-                       __get_cpu_var(current_kprobe) = NULL;
+                       __this_cpu_write(current_kprobe, NULL);
                }
 
                recycle_rp_inst(ri, &empty_rp);
@@ -1202,10 +1202,10 @@ static void __kprobes optimized_callback(struct optimized_kprobe *op,
                regs->ip = (unsigned long)op->kp.addr + INT3_SIZE;
                regs->orig_ax = ~0UL;
 
-               __get_cpu_var(current_kprobe) = &op->kp;
+               __this_cpu_write(current_kprobe, &op->kp);
                kcb->kprobe_status = KPROBE_HIT_ACTIVE;
                opt_pre_handler(&op->kp, regs);
-               __get_cpu_var(current_kprobe) = NULL;
+               __this_cpu_write(current_kprobe, NULL);
        }
        preempt_enable_no_resched();
 }
index c852041bfc3d5b70e792dad0cfd42fdd467c3f38..09c08a1c706f0993a59475d8a7446c4cd2eecd93 100644 (file)
@@ -446,7 +446,7 @@ void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
        trace_power_start(POWER_CSTATE, (ax>>4)+1, smp_processor_id());
        trace_cpu_idle((ax>>4)+1, smp_processor_id());
        if (!need_resched()) {
-               if (cpu_has(&current_cpu_data, X86_FEATURE_CLFLUSH_MONITOR))
+               if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR))
                        clflush((void *)&current_thread_info()->flags);
 
                __monitor((void *)&current_thread_info()->flags, 0, 0);
@@ -462,7 +462,7 @@ static void mwait_idle(void)
        if (!need_resched()) {
                trace_power_start(POWER_CSTATE, 1, smp_processor_id());
                trace_cpu_idle(1, smp_processor_id());
-               if (cpu_has(&current_cpu_data, X86_FEATURE_CLFLUSH_MONITOR))
+               if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR))
                        clflush((void *)&current_thread_info()->flags);
 
                __monitor((void *)&current_thread_info()->flags, 0, 0);
index ee886fe10ef4eb8515ae1d2431c0ce8ad3e8dd89..c7149c96d0795f592d2c24252ef471bb310aa471 100644 (file)
@@ -427,7 +427,7 @@ void __cpuinit set_cpu_sibling_map(int cpu)
 
        cpumask_set_cpu(cpu, c->llc_shared_map);
 
-       if (current_cpu_data.x86_max_cores == 1) {
+       if (__this_cpu_read(cpu_info.x86_max_cores) == 1) {
                cpumask_copy(cpu_core_mask(cpu), cpu_sibling_mask(cpu));
                c->booted_cores = 1;
                return;
@@ -1089,7 +1089,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 
        preempt_disable();
        smp_cpu_index_default();
-       current_cpu_data = boot_cpu_data;
+       memcpy(__this_cpu_ptr(&cpu_info), &boot_cpu_data, sizeof(cpu_info));
        cpumask_copy(cpu_callin_mask, cpumask_of(0));
        mb();
        /*
@@ -1383,7 +1383,7 @@ void play_dead_common(void)
 
        mb();
        /* Ack it */
-       __get_cpu_var(cpu_state) = CPU_DEAD;
+       __this_cpu_write(cpu_state, CPU_DEAD);
 
        /*
         * With physical CPU hotplug, we should halt the cpu
@@ -1403,11 +1403,11 @@ static inline void mwait_play_dead(void)
        int i;
        void *mwait_ptr;
 
-       if (!cpu_has(&current_cpu_data, X86_FEATURE_MWAIT))
+       if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_MWAIT))
                return;
-       if (!cpu_has(&current_cpu_data, X86_FEATURE_CLFLSH))
+       if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLSH))
                return;
-       if (current_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
+       if (__this_cpu_read(cpu_info.cpuid_level) < CPUID_MWAIT_LEAF)
                return;
 
        eax = CPUID_MWAIT_LEAF;
@@ -1458,7 +1458,7 @@ static inline void mwait_play_dead(void)
 
 static inline void hlt_play_dead(void)
 {
-       if (current_cpu_data.x86 >= 4)
+       if (__this_cpu_read(cpu_info.x86) >= 4)
                wbinvd();
 
        while (1) {
index 356a0d455cf997cb1bd586d3a13fd8a7c16d4d3c..03d2ea82f35ac7b8dab7950cd2324685304463fb 100644 (file)
@@ -659,7 +659,7 @@ void restore_sched_clock_state(void)
 
        local_irq_save(flags);
 
-       __get_cpu_var(cyc2ns_offset) = 0;
+       __this_cpu_write(cyc2ns_offset, 0);
        offset = cyc2ns_suspend - sched_clock();
 
        for_each_possible_cpu(cpu)
index b989e1f1e5d36b732d1d9c864f369b39a7459105..46a368cb651ea6abb031bc4b2543c92c3ccbb51d 100644 (file)
@@ -976,7 +976,7 @@ static inline u64 nsec_to_cycles(u64 nsec)
        if (kvm_tsc_changes_freq())
                printk_once(KERN_WARNING
                 "kvm: unreliable cycle conversion on adjustable rate TSC\n");
-       ret = nsec * __get_cpu_var(cpu_tsc_khz);
+       ret = nsec * __this_cpu_read(cpu_tsc_khz);
        do_div(ret, USEC_PER_SEC);
        return ret;
 }
@@ -1061,7 +1061,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
        local_irq_save(flags);
        kvm_get_msr(v, MSR_IA32_TSC, &tsc_timestamp);
        kernel_ns = get_kernel_ns();
-       this_tsc_khz = __get_cpu_var(cpu_tsc_khz);
+       this_tsc_khz = __this_cpu_read(cpu_tsc_khz);
 
        if (unlikely(this_tsc_khz == 0)) {
                local_irq_restore(flags);
@@ -4427,7 +4427,7 @@ EXPORT_SYMBOL_GPL(kvm_fast_pio_out);
 
 static void tsc_bad(void *info)
 {
-       __get_cpu_var(cpu_tsc_khz) = 0;
+       __this_cpu_write(cpu_tsc_khz, 0);
 }
 
 static void tsc_khz_changed(void *data)
@@ -4441,7 +4441,7 @@ static void tsc_khz_changed(void *data)
                khz = cpufreq_quick_get(raw_smp_processor_id());
        if (!khz)
                khz = tsc_khz;
-       __get_cpu_var(cpu_tsc_khz) = khz;
+       __this_cpu_write(cpu_tsc_khz, khz);
 }
 
 static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
index ff485d361182f814624e238e1ebc418c28c05e79..fc45ba887d051e504dd592be40ec2e78d70eea33 100644 (file)
@@ -121,7 +121,7 @@ inline void __const_udelay(unsigned long xloops)
        asm("mull %%edx"
                :"=d" (xloops), "=&a" (d0)
                :"1" (xloops), "0"
-               (cpu_data(raw_smp_processor_id()).loops_per_jiffy * (HZ/4)));
+               (this_cpu_read(cpu_info.loops_per_jiffy) * (HZ/4)));
 
        __delay(++xloops);
 }
index 358c8b9c96a79c725766e1627544486eb312a0bc..f24a8533bcdf11087d9c08e143ac89436768703e 100644 (file)
@@ -143,7 +143,7 @@ static inline int has_mux(void)
 
 inline int op_x86_phys_to_virt(int phys)
 {
-       return __get_cpu_var(switch_index) + phys;
+       return __this_cpu_read(switch_index) + phys;
 }
 
 inline int op_x86_virt_to_phys(int virt)
index d769cda540823e12a0dbfbdba923ec481f07abfd..94b745045e450932434a7c1b737c06b1721def16 100644 (file)
@@ -95,8 +95,8 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model,
                 * counter width:
                 */
                if (!(eax.split.version_id == 0 &&
-                       current_cpu_data.x86 == 6 &&
-                               current_cpu_data.x86_model == 15)) {
+                       __this_cpu_read(cpu_info.x86) == 6 &&
+                               __this_cpu_read(cpu_info.x86_model) == 15)) {
 
                        if (counter_width < eax.split.bit_width)
                                counter_width = eax.split.bit_width;
@@ -235,8 +235,8 @@ static void arch_perfmon_setup_counters(void)
        eax.full = cpuid_eax(0xa);
 
        /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */
-       if (eax.split.version_id == 0 && current_cpu_data.x86 == 6 &&
-               current_cpu_data.x86_model == 15) {
+       if (eax.split.version_id == 0 && __this_cpu_read(cpu_info.x86) == 6 &&
+               __this_cpu_read(cpu_info.x86_model) == 15) {
                eax.split.version_id = 2;
                eax.split.num_counters = 2;
                eax.split.bit_width = 40;
index 44dcad43989dc983af51863fac28677e2cfdaaee..7e8d3bc80af6969b5ae5e1a35ab15463000fd7eb 100644 (file)
@@ -574,8 +574,8 @@ static void xen_write_idt_entry(gate_desc *dt, int entrynum, const gate_desc *g)
 
        preempt_disable();
 
-       start = __get_cpu_var(idt_desc).address;
-       end = start + __get_cpu_var(idt_desc).size + 1;
+       start = __this_cpu_read(idt_desc.address);
+       end = start + __this_cpu_read(idt_desc.size) + 1;
 
        xen_mc_flush();
 
@@ -1174,6 +1174,15 @@ asmlinkage void __init xen_start_kernel(void)
 
        xen_smp_init();
 
+#ifdef CONFIG_ACPI_NUMA
+       /*
+        * The pages we from Xen are not related to machine pages, so
+        * any NUMA information the kernel tries to get from ACPI will
+        * be meaningless.  Prevent it from trying.
+        */
+       acpi_numa = -1;
+#endif
+
        pgd = (pgd_t *)xen_start_info->pt_base;
 
        if (!xen_initial_domain())
@@ -1256,25 +1265,6 @@ asmlinkage void __init xen_start_kernel(void)
 #endif
 }
 
-static uint32_t xen_cpuid_base(void)
-{
-       uint32_t base, eax, ebx, ecx, edx;
-       char signature[13];
-
-       for (base = 0x40000000; base < 0x40010000; base += 0x100) {
-               cpuid(base, &eax, &ebx, &ecx, &edx);
-               *(uint32_t *)(signature + 0) = ebx;
-               *(uint32_t *)(signature + 4) = ecx;
-               *(uint32_t *)(signature + 8) = edx;
-               signature[12] = 0;
-
-               if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
-                       return base;
-       }
-
-       return 0;
-}
-
 static int init_hvm_pv_info(int *major, int *minor)
 {
        uint32_t eax, ebx, ecx, edx, pages, msr, base;
@@ -1384,6 +1374,18 @@ static bool __init xen_hvm_platform(void)
        return true;
 }
 
+bool xen_hvm_need_lapic(void)
+{
+       if (xen_pv_domain())
+               return false;
+       if (!xen_hvm_domain())
+               return false;
+       if (xen_feature(XENFEAT_hvm_pirqs) && xen_have_vector_callback)
+               return false;
+       return true;
+}
+EXPORT_SYMBOL_GPL(xen_hvm_need_lapic);
+
 const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = {
        .name                   = "Xen HVM",
        .detect                 = xen_hvm_platform,
index 9e565da5d1f730f50d41fca98f4fbb86c69b5f29..4ec8035e3216208a94c960624befa606aed79884 100644 (file)
@@ -22,7 +22,7 @@ static inline void xen_mc_batch(void)
        unsigned long flags;
        /* need to disable interrupts until this entry is complete */
        local_irq_save(flags);
-       __get_cpu_var(xen_mc_irq_flags) = flags;
+       __this_cpu_write(xen_mc_irq_flags, flags);
 }
 
 static inline struct multicall_space xen_mc_entry(size_t args)
index 23e061b9327bc45b9ba64024559c87202f7602b0..cc9b1e182fcfad86bc67b56a8e172fb73d9e9ecf 100644 (file)
@@ -159,8 +159,8 @@ static inline struct xen_spinlock *spinning_lock(struct xen_spinlock *xl)
 {
        struct xen_spinlock *prev;
 
-       prev = __get_cpu_var(lock_spinners);
-       __get_cpu_var(lock_spinners) = xl;
+       prev = __this_cpu_read(lock_spinners);
+       __this_cpu_write(lock_spinners, xl);
 
        wmb();                  /* set lock of interest before count */
 
@@ -179,14 +179,14 @@ static inline void unspinning_lock(struct xen_spinlock *xl, struct xen_spinlock
        asm(LOCK_PREFIX " decw %0"
            : "+m" (xl->spinners) : : "memory");
        wmb();                  /* decrement count before restoring lock */
-       __get_cpu_var(lock_spinners) = prev;
+       __this_cpu_write(lock_spinners, prev);
 }
 
 static noinline int xen_spin_lock_slow(struct arch_spinlock *lock, bool irq_enable)
 {
        struct xen_spinlock *xl = (struct xen_spinlock *)lock;
        struct xen_spinlock *prev;
-       int irq = __get_cpu_var(lock_kicker_irq);
+       int irq = __this_cpu_read(lock_kicker_irq);
        int ret;
        u64 start;
 
index 5da5e53fb94c20bf6c244dce734e515c92d10b34..067759e3d6a525b53198673d6029ec4d6328cae7 100644 (file)
@@ -135,24 +135,24 @@ static void do_stolen_accounting(void)
 
        /* Add the appropriate number of ticks of stolen time,
           including any left-overs from last time. */
-       stolen = runnable + offline + __get_cpu_var(xen_residual_stolen);
+       stolen = runnable + offline + __this_cpu_read(xen_residual_stolen);
 
        if (stolen < 0)
                stolen = 0;
 
        ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen);
-       __get_cpu_var(xen_residual_stolen) = stolen;
+       __this_cpu_write(xen_residual_stolen, stolen);
        account_steal_ticks(ticks);
 
        /* Add the appropriate number of ticks of blocked time,
           including any left-overs from last time. */
-       blocked += __get_cpu_var(xen_residual_blocked);
+       blocked += __this_cpu_read(xen_residual_blocked);
 
        if (blocked < 0)
                blocked = 0;
 
        ticks = iter_div_u64_rem(blocked, NS_PER_TICK, &blocked);
-       __get_cpu_var(xen_residual_blocked) = blocked;
+       __this_cpu_write(xen_residual_blocked, blocked);
        account_idle_ticks(ticks);
 }
 
index dcb38f8ddfda09142f5962cfcfe38b9aa9fc5570..a765b823aa9e91066c417dacca634abe9ae9c6e5 100644 (file)
@@ -746,7 +746,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
        struct acpi_processor *pr;
        struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
 
-       pr = __get_cpu_var(processors);
+       pr = __this_cpu_read(processors);
 
        if (unlikely(!pr))
                return 0;
@@ -787,7 +787,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        s64 idle_time_ns;
        s64 idle_time;
 
-       pr = __get_cpu_var(processors);
+       pr = __this_cpu_read(processors);
 
        if (unlikely(!pr))
                return 0;
@@ -864,7 +864,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        s64 idle_time;
 
 
-       pr = __get_cpu_var(processors);
+       pr = __this_cpu_read(processors);
 
        if (unlikely(!pr))
                return 0;
index 36e2319264bd33d7918979105a4f641da36d3dcd..c6b298d4c136c54a40fa7b4e4c13361000535642 100644 (file)
@@ -2,6 +2,14 @@
 # SATA/PATA driver configuration
 #
 
+config HAVE_PATA_PLATFORM
+       bool
+       help
+         This is an internal configuration node for any machine that
+         uses pata-platform driver to enable the relevant driver in the
+         configuration structure without having to submit endless patches
+         to update the PATA_PLATFORM entry.
+
 menuconfig ATA
        tristate "Serial ATA and Parallel ATA drivers"
        depends on HAS_IOMEM
@@ -90,6 +98,14 @@ config SATA_INIC162X
        help
          This option enables support for Initio 162x Serial ATA.
 
+config SATA_ACARD_AHCI
+       tristate "ACard AHCI variant (ATP 8620)"
+       depends on PCI
+       help
+         This option enables support for Acard.
+
+         If unsure, say N.
+
 config SATA_SIL24
        tristate "Silicon Image 3124/3132 SATA support"
        depends on PCI
@@ -400,11 +416,11 @@ config PATA_HPT37X
          If unsure, say N.
 
 config PATA_HPT3X2N
-       tristate "HPT 372N/302N PATA support"
+       tristate "HPT 371N/372N/302N PATA support"
        depends on PCI
        help
          This option enables support for the N variant HPT PATA
-         controllers via the new ATA layer
+         controllers via the new ATA layer.
 
          If unsure, say N.
 
@@ -765,14 +781,6 @@ config PATA_PCMCIA
 
          If unsure, say N.
 
-config HAVE_PATA_PLATFORM
-       bool
-       help
-         This is an internal configuration node for any machine that
-         uses pata-platform driver to enable the relevant driver in the
-         configuration structure without having to submit endless patches
-         to update the PATA_PLATFORM entry.
-
 config PATA_PLATFORM
        tristate "Generic platform device PATA support"
        depends on EMBEDDED || PPC || HAVE_PATA_PLATFORM
index 2b67c900a459865c694e0cf012ebcacbfd8f76bd..27291aad6ca7f5a022aefef220adeaa8f1865f8c 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_ATA)               += libata.o
 
 # non-SFF interface
 obj-$(CONFIG_SATA_AHCI)                += ahci.o libahci.o
+obj-$(CONFIG_SATA_ACARD_AHCI)  += acard-ahci.o libahci.o
 obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
 obj-$(CONFIG_SATA_FSL)         += sata_fsl.o
 obj-$(CONFIG_SATA_INIC162X)    += sata_inic162x.o
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
new file mode 100644 (file)
index 0000000..339c210
--- /dev/null
@@ -0,0 +1,528 @@
+
+/*
+ *  acard-ahci.c - ACard AHCI SATA support
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *                 Please ALWAYS copy linux-ide@vger.kernel.org
+ *                 on emails.
+ *
+ *  Copyright 2010 Red Hat, Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, 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; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * AHCI hardware documentation:
+ * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
+ * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/gfp.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include "ahci.h"
+
+#define DRV_NAME       "acard-ahci"
+#define DRV_VERSION    "1.0"
+
+/*
+  Received FIS structure limited to 80h.
+*/
+
+#define ACARD_AHCI_RX_FIS_SZ 128
+
+enum {
+       AHCI_PCI_BAR            = 5,
+};
+
+enum board_ids {
+       board_acard_ahci,
+};
+
+struct acard_sg {
+       __le32                  addr;
+       __le32                  addr_hi;
+       __le32                  reserved;
+       __le32                  size;    /* bit 31 (EOT) max==0x10000 (64k) */
+};
+
+static void acard_ahci_qc_prep(struct ata_queued_cmd *qc);
+static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
+static int acard_ahci_port_start(struct ata_port *ap);
+static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+
+#ifdef CONFIG_PM
+static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int acard_ahci_pci_device_resume(struct pci_dev *pdev);
+#endif
+
+static struct scsi_host_template acard_ahci_sht = {
+       AHCI_SHT("acard-ahci"),
+};
+
+static struct ata_port_operations acard_ops = {
+       .inherits               = &ahci_ops,
+       .qc_prep                = acard_ahci_qc_prep,
+       .qc_fill_rtf            = acard_ahci_qc_fill_rtf,
+       .port_start             = acard_ahci_port_start,
+};
+
+#define AHCI_HFLAGS(flags)     .private_data   = (void *)(flags)
+
+static const struct ata_port_info acard_ahci_port_info[] = {
+       [board_acard_ahci] =
+       {
+               AHCI_HFLAGS     (AHCI_HFLAG_NO_NCQ),
+               .flags          = AHCI_FLAG_COMMON,
+               .pio_mask       = ATA_PIO4,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &acard_ops,
+       },
+};
+
+static const struct pci_device_id acard_ahci_pci_tbl[] = {
+       /* ACard */
+       { PCI_VDEVICE(ARTOP, 0x000d), board_acard_ahci }, /* ATP8620 */
+
+       { }    /* terminate list */
+};
+
+static struct pci_driver acard_ahci_pci_driver = {
+       .name                   = DRV_NAME,
+       .id_table               = acard_ahci_pci_tbl,
+       .probe                  = acard_ahci_init_one,
+       .remove                 = ata_pci_remove_one,
+#ifdef CONFIG_PM
+       .suspend                = acard_ahci_pci_device_suspend,
+       .resume                 = acard_ahci_pci_device_resume,
+#endif
+};
+
+#ifdef CONFIG_PM
+static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       void __iomem *mmio = hpriv->mmio;
+       u32 ctl;
+
+       if (mesg.event & PM_EVENT_SUSPEND &&
+           hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "BIOS update required for suspend/resume\n");
+               return -EIO;
+       }
+
+       if (mesg.event & PM_EVENT_SLEEP) {
+               /* AHCI spec rev1.1 section 8.3.3:
+                * Software must disable interrupts prior to requesting a
+                * transition of the HBA to D3 state.
+                */
+               ctl = readl(mmio + HOST_CTL);
+               ctl &= ~HOST_IRQ_EN;
+               writel(ctl, mmio + HOST_CTL);
+               readl(mmio + HOST_CTL); /* flush */
+       }
+
+       return ata_pci_device_suspend(pdev, mesg);
+}
+
+static int acard_ahci_pci_device_resume(struct pci_dev *pdev)
+{
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
+
+       if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+               rc = ahci_reset_controller(host);
+               if (rc)
+                       return rc;
+
+               ahci_init_controller(host);
+       }
+
+       ata_host_resume(host);
+
+       return 0;
+}
+#endif
+
+static int acard_ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
+{
+       int rc;
+
+       if (using_dac &&
+           !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+               if (rc) {
+                       rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+                       if (rc) {
+                               dev_printk(KERN_ERR, &pdev->dev,
+                                          "64-bit DMA enable failed\n");
+                               return rc;
+                       }
+               }
+       } else {
+               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (rc) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit DMA enable failed\n");
+                       return rc;
+               }
+               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (rc) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit consistent DMA enable failed\n");
+                       return rc;
+               }
+       }
+       return 0;
+}
+
+static void acard_ahci_pci_print_info(struct ata_host *host)
+{
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       u16 cc;
+       const char *scc_s;
+
+       pci_read_config_word(pdev, 0x0a, &cc);
+       if (cc == PCI_CLASS_STORAGE_IDE)
+               scc_s = "IDE";
+       else if (cc == PCI_CLASS_STORAGE_SATA)
+               scc_s = "SATA";
+       else if (cc == PCI_CLASS_STORAGE_RAID)
+               scc_s = "RAID";
+       else
+               scc_s = "unknown";
+
+       ahci_print_info(host, scc_s);
+}
+
+static unsigned int acard_ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
+{
+       struct scatterlist *sg;
+       struct acard_sg *acard_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
+       unsigned int si, last_si = 0;
+
+       VPRINTK("ENTER\n");
+
+       /*
+        * Next, the S/G list.
+        */
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
+               dma_addr_t addr = sg_dma_address(sg);
+               u32 sg_len = sg_dma_len(sg);
+
+               /*
+                * ACard note:
+                * We must set an end-of-table (EOT) bit,
+                * and the segment cannot exceed 64k (0x10000)
+                */
+               acard_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
+               acard_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+               acard_sg[si].size = cpu_to_le32(sg_len);
+               last_si = si;
+       }
+
+       acard_sg[last_si].size |= cpu_to_le32(1 << 31); /* set EOT */
+
+       return si;
+}
+
+static void acard_ahci_qc_prep(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct ahci_port_priv *pp = ap->private_data;
+       int is_atapi = ata_is_atapi(qc->tf.protocol);
+       void *cmd_tbl;
+       u32 opts;
+       const u32 cmd_fis_len = 5; /* five dwords */
+       unsigned int n_elem;
+
+       /*
+        * Fill in command table information.  First, the header,
+        * a SATA Register - Host to Device command FIS.
+        */
+       cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
+
+       ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
+       if (is_atapi) {
+               memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
+               memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
+       }
+
+       n_elem = 0;
+       if (qc->flags & ATA_QCFLAG_DMAMAP)
+               n_elem = acard_ahci_fill_sg(qc, cmd_tbl);
+
+       /*
+        * Fill in command slot information.
+        *
+        * ACard note: prd table length not filled in
+        */
+       opts = cmd_fis_len | (qc->dev->link->pmp << 12);
+       if (qc->tf.flags & ATA_TFLAG_WRITE)
+               opts |= AHCI_CMD_WRITE;
+       if (is_atapi)
+               opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
+
+       ahci_fill_cmd_slot(pp, qc->tag, opts);
+}
+
+static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+       struct ahci_port_priv *pp = qc->ap->private_data;
+       u8 *rx_fis = pp->rx_fis;
+
+       if (pp->fbs_enabled)
+               rx_fis += qc->dev->link->pmp * ACARD_AHCI_RX_FIS_SZ;
+
+       /*
+        * After a successful execution of an ATA PIO data-in command,
+        * the device doesn't send D2H Reg FIS to update the TF and
+        * the host should take TF and E_Status from the preceding PIO
+        * Setup FIS.
+        */
+       if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
+           !(qc->flags & ATA_QCFLAG_FAILED)) {
+               ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
+               qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15];
+       } else
+               ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
+
+       return true;
+}
+
+static int acard_ahci_port_start(struct ata_port *ap)
+{
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       struct device *dev = ap->host->dev;
+       struct ahci_port_priv *pp;
+       void *mem;
+       dma_addr_t mem_dma;
+       size_t dma_sz, rx_fis_sz;
+
+       pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+       if (!pp)
+               return -ENOMEM;
+
+       /* check FBS capability */
+       if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
+               void __iomem *port_mmio = ahci_port_base(ap);
+               u32 cmd = readl(port_mmio + PORT_CMD);
+               if (cmd & PORT_CMD_FBSCP)
+                       pp->fbs_supported = true;
+               else if (hpriv->flags & AHCI_HFLAG_YES_FBS) {
+                       dev_printk(KERN_INFO, dev,
+                                  "port %d can do FBS, forcing FBSCP\n",
+                                  ap->port_no);
+                       pp->fbs_supported = true;
+               } else
+                       dev_printk(KERN_WARNING, dev,
+                                  "port %d is not capable of FBS\n",
+                                  ap->port_no);
+       }
+
+       if (pp->fbs_supported) {
+               dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ;
+               rx_fis_sz = ACARD_AHCI_RX_FIS_SZ * 16;
+       } else {
+               dma_sz = AHCI_PORT_PRIV_DMA_SZ;
+               rx_fis_sz = ACARD_AHCI_RX_FIS_SZ;
+       }
+
+       mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
+       if (!mem)
+               return -ENOMEM;
+       memset(mem, 0, dma_sz);
+
+       /*
+        * First item in chunk of DMA memory: 32-slot command table,
+        * 32 bytes each in size
+        */
+       pp->cmd_slot = mem;
+       pp->cmd_slot_dma = mem_dma;
+
+       mem += AHCI_CMD_SLOT_SZ;
+       mem_dma += AHCI_CMD_SLOT_SZ;
+
+       /*
+        * Second item: Received-FIS area
+        */
+       pp->rx_fis = mem;
+       pp->rx_fis_dma = mem_dma;
+
+       mem += rx_fis_sz;
+       mem_dma += rx_fis_sz;
+
+       /*
+        * Third item: data area for storing a single command
+        * and its scatter-gather table
+        */
+       pp->cmd_tbl = mem;
+       pp->cmd_tbl_dma = mem_dma;
+
+       /*
+        * Save off initial list of interrupts to be enabled.
+        * This could be changed later
+        */
+       pp->intr_mask = DEF_PORT_IRQ;
+
+       ap->private_data = pp;
+
+       /* engage engines, captain */
+       return ahci_port_resume(ap);
+}
+
+static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       static int printed_version;
+       unsigned int board_id = ent->driver_data;
+       struct ata_port_info pi = acard_ahci_port_info[board_id];
+       const struct ata_port_info *ppi[] = { &pi, NULL };
+       struct device *dev = &pdev->dev;
+       struct ahci_host_priv *hpriv;
+       struct ata_host *host;
+       int n_ports, i, rc;
+
+       VPRINTK("ENTER\n");
+
+       WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
+
+       if (!printed_version++)
+               dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+       /* acquire resources */
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+
+       /* AHCI controllers often implement SFF compatible interface.
+        * Grab all PCI BARs just in case.
+        */
+       rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
+       if (rc == -EBUSY)
+               pcim_pin_device(pdev);
+       if (rc)
+               return rc;
+
+       hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+       if (!hpriv)
+               return -ENOMEM;
+       hpriv->flags |= (unsigned long)pi.private_data;
+
+       if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
+               pci_enable_msi(pdev);
+
+       hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
+
+       /* save initial config */
+       ahci_save_initial_config(&pdev->dev, hpriv, 0, 0);
+
+       /* prepare host */
+       if (hpriv->cap & HOST_CAP_NCQ)
+               pi.flags |= ATA_FLAG_NCQ;
+
+       if (hpriv->cap & HOST_CAP_PMP)
+               pi.flags |= ATA_FLAG_PMP;
+
+       ahci_set_em_messages(hpriv, &pi);
+
+       /* CAP.NP sometimes indicate the index of the last enabled
+        * port, at other times, that of the last possible port, so
+        * determining the maximum port number requires looking at
+        * both CAP.NP and port_map.
+        */
+       n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+       if (!host)
+               return -ENOMEM;
+       host->private_data = hpriv;
+
+       if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+               host->flags |= ATA_HOST_PARALLEL_SCAN;
+       else
+               printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+
+               ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
+               ata_port_pbar_desc(ap, AHCI_PCI_BAR,
+                                  0x100 + ap->port_no * 0x80, "port");
+
+               /* set initial link pm policy */
+               /*
+               ap->pm_policy = NOT_AVAILABLE;
+               */
+               /* disabled/not-implemented port */
+               if (!(hpriv->port_map & (1 << i)))
+                       ap->ops = &ata_dummy_port_ops;
+       }
+
+       /* initialize adapter */
+       rc = acard_ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
+       if (rc)
+               return rc;
+
+       rc = ahci_reset_controller(host);
+       if (rc)
+               return rc;
+
+       ahci_init_controller(host);
+       acard_ahci_pci_print_info(host);
+
+       pci_set_master(pdev);
+       return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
+                                &acard_ahci_sht);
+}
+
+static int __init acard_ahci_init(void)
+{
+       return pci_register_driver(&acard_ahci_pci_driver);
+}
+
+static void __exit acard_ahci_exit(void)
+{
+       pci_unregister_driver(&acard_ahci_pci_driver);
+}
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("ACard AHCI SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, acard_ahci_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(acard_ahci_init);
+module_exit(acard_ahci_exit);
index 329cbbb91284ad4dd3b7e4f486ea82f2737ae1b3..3e606c34f57ba58af87ab7014e51cc32d2f5d67b 100644 (file)
@@ -311,6 +311,8 @@ extern struct device_attribute *ahci_sdev_attrs[];
 
 extern struct ata_port_operations ahci_ops;
 
+void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+                       u32 opts);
 void ahci_save_initial_config(struct device *dev,
                              struct ahci_host_priv *hpriv,
                              unsigned int force_port_map,
@@ -326,6 +328,7 @@ int ahci_stop_engine(struct ata_port *ap);
 void ahci_start_engine(struct ata_port *ap);
 int ahci_check_ready(struct ata_link *link);
 int ahci_kick_engine(struct ata_port *ap);
+int ahci_port_resume(struct ata_port *ap);
 void ahci_set_em_messages(struct ahci_host_priv *hpriv,
                          struct ata_port_info *pi);
 int ahci_reset_em(struct ata_host *host);
index ebc08d65b3dd04c9af94da0d7146d3a165ce9803..26d452339e98f59fc483cbc85e9c53f56b2a0183 100644 (file)
@@ -87,10 +87,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
 static void ahci_postreset(struct ata_link *link, unsigned int *class);
 static void ahci_error_handler(struct ata_port *ap);
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
-static int ahci_port_resume(struct ata_port *ap);
 static void ahci_dev_config(struct ata_device *dev);
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
-                              u32 opts);
 #ifdef CONFIG_PM
 static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
 #endif
@@ -1133,8 +1130,8 @@ static unsigned int ahci_dev_classify(struct ata_port *ap)
        return ata_dev_classify(&tf);
 }
 
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
-                              u32 opts)
+void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+                       u32 opts)
 {
        dma_addr_t cmd_tbl_dma;
 
@@ -1145,6 +1142,7 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
        pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
        pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
 }
+EXPORT_SYMBOL_GPL(ahci_fill_cmd_slot);
 
 int ahci_kick_engine(struct ata_port *ap)
 {
@@ -1918,7 +1916,7 @@ static void ahci_pmp_detach(struct ata_port *ap)
        writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
 }
 
-static int ahci_port_resume(struct ata_port *ap)
+int ahci_port_resume(struct ata_port *ap)
 {
        ahci_power_up(ap);
        ahci_start_port(ap);
@@ -1930,6 +1928,7 @@ static int ahci_port_resume(struct ata_port *ap)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(ahci_port_resume);
 
 #ifdef CONFIG_PM
 static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
index f23d6d46b95b1bf7f4f19fb657f86cadc0ccd6b7..0a6a943b3779ec700af7f7bb5a30f220f0c1ab4d 100644 (file)
@@ -6128,7 +6128,7 @@ static void ata_port_detach(struct ata_port *ap)
        /* it better be dead now */
        WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
 
-       cancel_rearming_delayed_work(&ap->hotplug_task);
+       cancel_delayed_work_sync(&ap->hotplug_task);
 
  skip_eh:
        if (ap->pmp_link) {
index 66aa4bee80a659712b75e8b3949678d56e8bd5a3..5defc74973d751a6283b10ac40bc29f257abbedd 100644 (file)
@@ -346,12 +346,11 @@ struct device_attribute *ata_common_sdev_attrs[] = {
 };
 EXPORT_SYMBOL_GPL(ata_common_sdev_attrs);
 
-static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
-                                  void (*done)(struct scsi_cmnd *))
+static void ata_scsi_invalid_field(struct scsi_cmnd *cmd)
 {
        ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
        /* "Invalid field in cbd" */
-       done(cmd);
+       cmd->scsi_done(cmd);
 }
 
 /**
@@ -719,7 +718,6 @@ EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
  *     ata_scsi_qc_new - acquire new ata_queued_cmd reference
  *     @dev: ATA device to which the new command is attached
  *     @cmd: SCSI command that originated this ATA command
- *     @done: SCSI command completion function
  *
  *     Obtain a reference to an unused ata_queued_cmd structure,
  *     which is the basic libata structure representing a single
@@ -736,21 +734,20 @@ EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
  *     Command allocated, or %NULL if none available.
  */
 static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
-                                             struct scsi_cmnd *cmd,
-                                             void (*done)(struct scsi_cmnd *))
+                                             struct scsi_cmnd *cmd)
 {
        struct ata_queued_cmd *qc;
 
        qc = ata_qc_new_init(dev);
        if (qc) {
                qc->scsicmd = cmd;
-               qc->scsidone = done;
+               qc->scsidone = cmd->scsi_done;
 
                qc->sg = scsi_sglist(cmd);
                qc->n_elem = scsi_sg_count(cmd);
        } else {
                cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
-               done(cmd);
+               cmd->scsi_done(cmd);
        }
 
        return qc;
@@ -1735,7 +1732,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
  *     ata_scsi_translate - Translate then issue SCSI command to ATA device
  *     @dev: ATA device to which the command is addressed
  *     @cmd: SCSI command to execute
- *     @done: SCSI command completion function
  *     @xlat_func: Actor which translates @cmd to an ATA taskfile
  *
  *     Our ->queuecommand() function has decided that the SCSI
@@ -1759,7 +1755,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
  *     needs to be deferred.
  */
 static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
-                             void (*done)(struct scsi_cmnd *),
                              ata_xlat_func_t xlat_func)
 {
        struct ata_port *ap = dev->link->ap;
@@ -1768,7 +1763,7 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
 
        VPRINTK("ENTER\n");
 
-       qc = ata_scsi_qc_new(dev, cmd, done);
+       qc = ata_scsi_qc_new(dev, cmd);
        if (!qc)
                goto err_mem;
 
@@ -1804,14 +1799,14 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
 
 early_finish:
        ata_qc_free(qc);
-       qc->scsidone(cmd);
+       cmd->scsi_done(cmd);
        DPRINTK("EXIT - early finish (good or error)\n");
        return 0;
 
 err_did:
        ata_qc_free(qc);
        cmd->result = (DID_ERROR << 16);
-       qc->scsidone(cmd);
+       cmd->scsi_done(cmd);
 err_mem:
        DPRINTK("EXIT - internal\n");
        return 0;
@@ -3116,7 +3111,6 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
 }
 
 static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
-                                     void (*done)(struct scsi_cmnd *),
                                      struct ata_device *dev)
 {
        u8 scsi_op = scmd->cmnd[0];
@@ -3150,9 +3144,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
        }
 
        if (xlat_func)
-               rc = ata_scsi_translate(dev, scmd, done, xlat_func);
+               rc = ata_scsi_translate(dev, scmd, xlat_func);
        else
-               ata_scsi_simulate(dev, scmd, done);
+               ata_scsi_simulate(dev, scmd);
 
        return rc;
 
@@ -3160,7 +3154,7 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
        DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n",
                scmd->cmd_len, scsi_op, dev->cdb_len);
        scmd->result = DID_ERROR << 16;
-       done(scmd);
+       scmd->scsi_done(scmd);
        return 0;
 }
 
@@ -3199,7 +3193,7 @@ int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
 
        dev = ata_scsi_find_dev(ap, scsidev);
        if (likely(dev))
-               rc = __ata_scsi_queuecmd(cmd, cmd->scsi_done, dev);
+               rc = __ata_scsi_queuecmd(cmd, dev);
        else {
                cmd->result = (DID_BAD_TARGET << 16);
                cmd->scsi_done(cmd);
@@ -3214,7 +3208,6 @@ int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
  *     ata_scsi_simulate - simulate SCSI command on ATA device
  *     @dev: the target device
  *     @cmd: SCSI command being sent to device.
- *     @done: SCSI command completion function.
  *
  *     Interprets and directly executes a select list of SCSI commands
  *     that can be handled internally.
@@ -3223,8 +3216,7 @@ int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
  *     spin_lock_irqsave(host lock)
  */
 
-void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
-                     void (*done)(struct scsi_cmnd *))
+void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
 {
        struct ata_scsi_args args;
        const u8 *scsicmd = cmd->cmnd;
@@ -3233,17 +3225,17 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
        args.dev = dev;
        args.id = dev->id;
        args.cmd = cmd;
-       args.done = done;
+       args.done = cmd->scsi_done;
 
        switch(scsicmd[0]) {
        /* TODO: worth improving? */
        case FORMAT_UNIT:
-               ata_scsi_invalid_field(cmd, done);
+               ata_scsi_invalid_field(cmd);
                break;
 
        case INQUIRY:
                if (scsicmd[1] & 2)                /* is CmdDt set?  */
-                       ata_scsi_invalid_field(cmd, done);
+                       ata_scsi_invalid_field(cmd);
                else if ((scsicmd[1] & 1) == 0)    /* is EVPD clear? */
                        ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
                else switch (scsicmd[2]) {
@@ -3269,7 +3261,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
                        ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2);
                        break;
                default:
-                       ata_scsi_invalid_field(cmd, done);
+                       ata_scsi_invalid_field(cmd);
                        break;
                }
                break;
@@ -3281,7 +3273,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
 
        case MODE_SELECT:       /* unconditionally return */
        case MODE_SELECT_10:    /* bad-field-in-cdb */
-               ata_scsi_invalid_field(cmd, done);
+               ata_scsi_invalid_field(cmd);
                break;
 
        case READ_CAPACITY:
@@ -3292,7 +3284,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
                if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
                        ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
                else
-                       ata_scsi_invalid_field(cmd, done);
+                       ata_scsi_invalid_field(cmd);
                break;
 
        case REPORT_LUNS:
@@ -3302,7 +3294,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
        case REQUEST_SENSE:
                ata_scsi_set_sense(cmd, 0, 0, 0);
                cmd->result = (DRIVER_SENSE << 24);
-               done(cmd);
+               cmd->scsi_done(cmd);
                break;
 
        /* if we reach this, then writeback caching is disabled,
@@ -3324,14 +3316,14 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
                if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
                        ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
                else
-                       ata_scsi_invalid_field(cmd, done);
+                       ata_scsi_invalid_field(cmd);
                break;
 
        /* all other commands */
        default:
                ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
                /* "Invalid command operation code" */
-               done(cmd);
+               cmd->scsi_done(cmd);
                break;
        }
 }
@@ -3858,7 +3850,6 @@ EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
 /**
  *     ata_sas_queuecmd - Issue SCSI cdb to libata-managed device
  *     @cmd: SCSI command to be sent
- *     @done: Completion function, called when command is complete
  *     @ap:    ATA port to which the command is being sent
  *
  *     RETURNS:
@@ -3866,18 +3857,17 @@ EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
  *     0 otherwise.
  */
 
-int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
-                    struct ata_port *ap)
+int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
 {
        int rc = 0;
 
        ata_scsi_dump_cdb(ap, cmd);
 
        if (likely(ata_dev_enabled(ap->link.device)))
-               rc = __ata_scsi_queuecmd(cmd, done, ap->link.device);
+               rc = __ata_scsi_queuecmd(cmd, ap->link.device);
        else {
                cmd->result = (DID_BAD_TARGET << 16);
-               done(cmd);
+               cmd->scsi_done(cmd);
        }
        return rc;
 }
index 484697fef3867dce2c1926f0ad50bb53de3b40e7..af6141bb1ba3e6fb678f3b54a41846a9135ca865 100644 (file)
@@ -1320,7 +1320,7 @@ void ata_sff_flush_pio_task(struct ata_port *ap)
 {
        DPRINTK("ENTER\n");
 
-       cancel_rearming_delayed_work(&ap->sff_pio_task);
+       cancel_delayed_work_sync(&ap->sff_pio_task);
        ap->hsm_task_state = HSM_ST_IDLE;
 
        if (ata_msg_ctl(ap))
index 7688868557b95e7bd2231599178134bd3b13d6f9..d7e57db36bc835d83c11bcfb7aea1757cf46844e 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt366"
-#define DRV_VERSION    "0.6.8"
+#define DRV_VERSION    "0.6.9"
 
 struct hpt_clock {
        u8      xfer_mode;
@@ -110,18 +110,23 @@ static const struct hpt_clock hpt366_25[] = {
        {       0,              0x01208585      }
 };
 
-static const char *bad_ata33[] = {
-       "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
-       "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
-       "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+static const char * const bad_ata33[] = {
+       "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3",
+       "Maxtor 90845U3", "Maxtor 90650U2",
+       "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5",
+       "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+       "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6",
+       "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
        "Maxtor 90510D4",
        "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
-       "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
-       "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+       "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7",
+       "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+       "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5",
+       "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
        NULL
 };
 
-static const char *bad_ata66_4[] = {
+static const char * const bad_ata66_4[] = {
        "IBM-DTLA-307075",
        "IBM-DTLA-307060",
        "IBM-DTLA-307045",
@@ -140,12 +145,13 @@ static const char *bad_ata66_4[] = {
        NULL
 };
 
-static const char *bad_ata66_3[] = {
+static const char * const bad_ata66_3[] = {
        "WDC AC310200R",
        NULL
 };
 
-static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
+                              const char * const list[])
 {
        unsigned char model_num[ATA_ID_PROD_LEN + 1];
        int i = 0;
@@ -288,6 +294,7 @@ static struct ata_port_operations hpt366_port_ops = {
 static void hpt36x_init_chipset(struct pci_dev *dev)
 {
        u8 drive_fast;
+
        pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
        pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
        pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
@@ -349,16 +356,16 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
        /* PCI clocking determines the ATA timing values to use */
        /* info_hpt366 is safe against re-entry so we can scribble on it */
-       switch((reg1 & 0x700) >> 8) {
-               case 9:
-                       hpriv = &hpt366_40;
-                       break;
-               case 5:
-                       hpriv = &hpt366_25;
-                       break;
-               default:
-                       hpriv = &hpt366_33;
-                       break;
+       switch ((reg1 & 0x700) >> 8) {
+       case 9:
+               hpriv = &hpt366_40;
+               break;
+       case 5:
+               hpriv = &hpt366_25;
+               break;
+       default:
+               hpriv = &hpt366_33;
+               break;
        }
        /* Now kick off ATA set up */
        return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);
@@ -385,9 +392,9 @@ static const struct pci_device_id hpt36x[] = {
 };
 
 static struct pci_driver hpt36x_pci_driver = {
-       .name           = DRV_NAME,
+       .name           = DRV_NAME,
        .id_table       = hpt36x,
-       .probe          = hpt36x_init_one,
+       .probe          = hpt36x_init_one,
        .remove         = ata_pci_remove_one,
 #ifdef CONFIG_PM
        .suspend        = ata_pci_device_suspend,
index 9ae4c08305779a4cad19fbe466eb1ab48bc3053b..efdd18bc8663588d5db55942bea138fa353b6df6 100644 (file)
@@ -8,7 +8,7 @@
  * Copyright (C) 1999-2003             Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001         Sun Microsystems, Inc.
  * Portions Copyright (C) 2003         Red Hat Inc
- * Portions Copyright (C) 2005-2009    MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2010    MontaVista Software, Inc.
  *
  * TODO
  *     Look into engine reset on timeout errors. Should not be required.
@@ -24,7 +24,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt37x"
-#define DRV_VERSION    "0.6.15"
+#define DRV_VERSION    "0.6.18"
 
 struct hpt_clock {
        u8      xfer_speed;
@@ -210,7 +210,7 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
 {
        struct hpt_clock *clocks = ap->host->private_data;
 
-       while(clocks->xfer_speed) {
+       while (clocks->xfer_speed) {
                if (clocks->xfer_speed == speed)
                        return clocks->timing;
                clocks++;
@@ -219,7 +219,8 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
        return 0xffffffffU;     /* silence compiler warning */
 }
 
-static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
+                              const char * const list[])
 {
        unsigned char model_num[ATA_ID_PROD_LEN + 1];
        int i = 0;
@@ -237,18 +238,23 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, cons
        return 0;
 }
 
-static const char *bad_ata33[] = {
-       "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
-       "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
-       "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+static const char * const bad_ata33[] = {
+       "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3",
+       "Maxtor 90845U3", "Maxtor 90650U2",
+       "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5",
+       "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+       "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6",
+       "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
        "Maxtor 90510D4",
        "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
-       "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
-       "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+       "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7",
+       "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+       "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5",
+       "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
        NULL
 };
 
-static const char *bad_ata100_5[] = {
+static const char * const bad_ata100_5[] = {
        "IBM-DTLA-307075",
        "IBM-DTLA-307060",
        "IBM-DTLA-307045",
@@ -301,6 +307,22 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
        return mask;
 }
 
+/**
+ *     hpt372_filter   -       mode selection filter
+ *     @adev: ATA device
+ *     @mask: mode mask
+ *
+ *     The Marvell bridge chips used on the HighPoint SATA cards do not seem
+ *     to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
+ */
+static unsigned long hpt372_filter(struct ata_device *adev, unsigned long mask)
+{
+       if (ata_id_is_sata(adev->id))
+               mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA);
+
+       return mask;
+}
+
 /**
  *     hpt37x_cable_detect     -       Detect the cable type
  *     @ap: ATA port to detect on
@@ -373,6 +395,7 @@ static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
                { 0x50, 1, 0x04, 0x04 },
                { 0x54, 1, 0x04, 0x04 }
        };
+
        if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
                return -ENOENT;
 
@@ -586,11 +609,11 @@ static struct ata_port_operations hpt370a_port_ops = {
 };
 
 /*
- *     Configuration for HPT372, HPT371, HPT302. Slightly different PIO
- *     and DMA mode setting functionality.
+ *     Configuration for HPT371 and HPT302. Slightly different PIO and DMA
+ *     mode setting functionality.
  */
 
-static struct ata_port_operations hpt372_port_ops = {
+static struct ata_port_operations hpt302_port_ops = {
        .inherits       = &ata_bmdma_port_ops,
 
        .bmdma_stop     = hpt37x_bmdma_stop,
@@ -602,7 +625,17 @@ static struct ata_port_operations hpt372_port_ops = {
 };
 
 /*
- *     Configuration for HPT374. Mode setting works like 372 and friends
+ *     Configuration for HPT372. Mode setting works like 371 and 302
+ *     but we have a mode filter.
+ */
+
+static struct ata_port_operations hpt372_port_ops = {
+       .inherits       = &hpt302_port_ops,
+       .mode_filter    = hpt372_filter,
+};
+
+/*
+ *     Configuration for HPT374. Mode setting and filtering works like 372
  *     but we have a different cable detection procedure for function 1.
  */
 
@@ -647,12 +680,12 @@ static int hpt37x_calibrate_dpll(struct pci_dev *dev)
        u32 reg5c;
        int tries;
 
-       for(tries = 0; tries < 0x5000; tries++) {
+       for (tries = 0; tries < 0x5000; tries++) {
                udelay(50);
                pci_read_config_byte(dev, 0x5b, &reg5b);
                if (reg5b & 0x80) {
                        /* See if it stays set */
-                       for(tries = 0; tries < 0x1000; tries ++) {
+                       for (tries = 0; tries < 0x1000; tries++) {
                                pci_read_config_byte(dev, 0x5b, &reg5b);
                                /* Failed ? */
                                if ((reg5b & 0x80) == 0)
@@ -660,7 +693,7 @@ static int hpt37x_calibrate_dpll(struct pci_dev *dev)
                        }
                        /* Turn off tuning, we have the DPLL set */
                        pci_read_config_dword(dev, 0x5c, &reg5c);
-                       pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
+                       pci_write_config_dword(dev, 0x5c, reg5c & ~0x100);
                        return 1;
                }
        }
@@ -672,6 +705,7 @@ static u32 hpt374_read_freq(struct pci_dev *pdev)
 {
        u32 freq;
        unsigned long io_base = pci_resource_start(pdev, 4);
+
        if (PCI_FUNC(pdev->devfn) & 1) {
                struct pci_dev *pdev_0;
 
@@ -737,23 +771,23 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                .udma_mask = ATA_UDMA5,
                .port_ops = &hpt370a_port_ops
        };
-       /* HPT370 - UDMA100 */
+       /* HPT370 - UDMA66 */
        static const struct ata_port_info info_hpt370_33 = {
                .flags = ATA_FLAG_SLAVE_POSS,
                .pio_mask = ATA_PIO4,
                .mwdma_mask = ATA_MWDMA2,
-               .udma_mask = ATA_UDMA5,
+               .udma_mask = ATA_UDMA4,
                .port_ops = &hpt370_port_ops
        };
-       /* HPT370A - UDMA100 */
+       /* HPT370A - UDMA66 */
        static const struct ata_port_info info_hpt370a_33 = {
                .flags = ATA_FLAG_SLAVE_POSS,
                .pio_mask = ATA_PIO4,
                .mwdma_mask = ATA_MWDMA2,
-               .udma_mask = ATA_UDMA5,
+               .udma_mask = ATA_UDMA4,
                .port_ops = &hpt370a_port_ops
        };
-       /* HPT371, 372 and friends - UDMA133 */
+       /* HPT372 - UDMA133 */
        static const struct ata_port_info info_hpt372 = {
                .flags = ATA_FLAG_SLAVE_POSS,
                .pio_mask = ATA_PIO4,
@@ -761,6 +795,14 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                .udma_mask = ATA_UDMA6,
                .port_ops = &hpt372_port_ops
        };
+       /* HPT371, 302 - UDMA133 */
+       static const struct ata_port_info info_hpt302 = {
+               .flags = ATA_FLAG_SLAVE_POSS,
+               .pio_mask = ATA_PIO4,
+               .mwdma_mask = ATA_MWDMA2,
+               .udma_mask = ATA_UDMA6,
+               .port_ops = &hpt302_port_ops
+       };
        /* HPT374 - UDMA100, function 1 uses different prereset method */
        static const struct ata_port_info info_hpt374_fn0 = {
                .flags = ATA_FLAG_SLAVE_POSS,
@@ -805,64 +847,68 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                if (rev == 6)
                        return -ENODEV;
 
-               switch(rev) {
-                       case 3:
-                               ppi[0] = &info_hpt370;
-                               chip_table = &hpt370;
-                               prefer_dpll = 0;
-                               break;
-                       case 4:
-                               ppi[0] = &info_hpt370a;
-                               chip_table = &hpt370a;
-                               prefer_dpll = 0;
-                               break;
-                       case 5:
-                               ppi[0] = &info_hpt372;
-                               chip_table = &hpt372;
-                               break;
-                       default:
-                               printk(KERN_ERR "pata_hpt37x: Unknown HPT366 "
-                                      "subtype, please report (%d).\n", rev);
-                               return -ENODEV;
+               switch (rev) {
+               case 3:
+                       ppi[0] = &info_hpt370;
+                       chip_table = &hpt370;
+                       prefer_dpll = 0;
+                       break;
+               case 4:
+                       ppi[0] = &info_hpt370a;
+                       chip_table = &hpt370a;
+                       prefer_dpll = 0;
+                       break;
+               case 5:
+                       ppi[0] = &info_hpt372;
+                       chip_table = &hpt372;
+                       break;
+               default:
+                       printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype, "
+                              "please report (%d).\n", rev);
+                       return -ENODEV;
                }
        } else {
-               switch(dev->device) {
-                       case PCI_DEVICE_ID_TTI_HPT372:
-                               /* 372N if rev >= 2*/
-                               if (rev >= 2)
-                                       return -ENODEV;
-                               ppi[0] = &info_hpt372;
-                               chip_table = &hpt372a;
-                               break;
-                       case PCI_DEVICE_ID_TTI_HPT302:
-                               /* 302N if rev > 1 */
-                               if (rev > 1)
-                                       return -ENODEV;
-                               ppi[0] = &info_hpt372;
-                               /* Check this */
-                               chip_table = &hpt302;
-                               break;
-                       case PCI_DEVICE_ID_TTI_HPT371:
-                               if (rev > 1)
-                                       return -ENODEV;
-                               ppi[0] = &info_hpt372;
-                               chip_table = &hpt371;
-                               /* Single channel device, master is not present
-                                  but the BIOS (or us for non x86) must mark it
-                                  absent */
-                               pci_read_config_byte(dev, 0x50, &mcr1);
-                               mcr1 &= ~0x04;
-                               pci_write_config_byte(dev, 0x50, mcr1);
-                               break;
-                       case PCI_DEVICE_ID_TTI_HPT374:
-                               chip_table = &hpt374;
-                               if (!(PCI_FUNC(dev->devfn) & 1))
-                                       *ppi = &info_hpt374_fn0;
-                               else
-                                       *ppi = &info_hpt374_fn1;
-                               break;
-                       default:
-                               printk(KERN_ERR "pata_hpt37x: PCI table is bogus please report (%d).\n", dev->device);
+               switch (dev->device) {
+               case PCI_DEVICE_ID_TTI_HPT372:
+                       /* 372N if rev >= 2 */
+                       if (rev >= 2)
+                               return -ENODEV;
+                       ppi[0] = &info_hpt372;
+                       chip_table = &hpt372a;
+                       break;
+               case PCI_DEVICE_ID_TTI_HPT302:
+                       /* 302N if rev > 1 */
+                       if (rev > 1)
+                               return -ENODEV;
+                       ppi[0] = &info_hpt302;
+                       /* Check this */
+                       chip_table = &hpt302;
+                       break;
+               case PCI_DEVICE_ID_TTI_HPT371:
+                       if (rev > 1)
+                               return -ENODEV;
+                       ppi[0] = &info_hpt302;
+                       chip_table = &hpt371;
+                       /*
+                        * Single channel device, master is not present
+                        * but the BIOS (or us for non x86) must mark it
+                        * absent
+                        */
+                       pci_read_config_byte(dev, 0x50, &mcr1);
+                       mcr1 &= ~0x04;
+                       pci_write_config_byte(dev, 0x50, mcr1);
+                       break;
+               case PCI_DEVICE_ID_TTI_HPT374:
+                       chip_table = &hpt374;
+                       if (!(PCI_FUNC(dev->devfn) & 1))
+                               *ppi = &info_hpt374_fn0;
+                       else
+                               *ppi = &info_hpt374_fn1;
+                       break;
+               default:
+                       printk(KERN_ERR
+                              "pata_hpt37x: PCI table is bogus, please report (%d).\n",
+                              dev->device);
                                return -ENODEV;
                }
        }
@@ -893,9 +939,11 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (chip_table == &hpt372a)
                outb(0x0e, iobase + 0x9c);
 
-       /* Some devices do not let this value be accessed via PCI space
-          according to the old driver. In addition we must use the value
-          from FN 0 on the HPT374 */
+       /*
+        * Some devices do not let this value be accessed via PCI space
+        * according to the old driver. In addition we must use the value
+        * from FN 0 on the HPT374.
+        */
 
        if (chip_table == &hpt374) {
                freq = hpt374_read_freq(dev);
@@ -909,10 +957,11 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                u8 sr;
                u32 total = 0;
 
-               printk(KERN_WARNING "pata_hpt37x: BIOS has not set timing clocks.\n");
+               printk(KERN_WARNING
+                      "pata_hpt37x: BIOS has not set timing clocks.\n");
 
                /* This is the process the HPT371 BIOS is reported to use */
-               for(i = 0; i < 128; i++) {
+               for (i = 0; i < 128; i++) {
                        pci_read_config_byte(dev, 0x78, &sr);
                        total += sr & 0x1FF;
                        udelay(15);
@@ -947,17 +996,22 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
                /* Select the DPLL clock. */
                pci_write_config_byte(dev, 0x5b, 0x21);
-               pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
+               pci_write_config_dword(dev, 0x5C,
+                                      (f_high << 16) | f_low | 0x100);
 
-               for(adjust = 0; adjust < 8; adjust++) {
+               for (adjust = 0; adjust < 8; adjust++) {
                        if (hpt37x_calibrate_dpll(dev))
                                break;
-                       /* See if it'll settle at a fractionally different clock */
+                       /*
+                        * See if it'll settle at a fractionally
+                        * different clock
+                        */
                        if (adjust & 1)
                                f_low -= adjust >> 1;
                        else
                                f_high += adjust >> 1;
-                       pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
+                       pci_write_config_dword(dev, 0x5C,
+                                              (f_high << 16) | f_low | 0x100);
                }
                if (adjust == 8) {
                        printk(KERN_ERR "pata_hpt37x: DPLL did not stabilize!\n");
@@ -976,7 +1030,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                 *      Perform a final fixup. Note that we will have used the
                 *      DPLL on the HPT372 which means we don't have to worry
                 *      about lack of UDMA133 support on lower clocks
-                */
+                */
 
                if (clock_slot < 2 && ppi[0] == &info_hpt370)
                        ppi[0] = &info_hpt370_33;
@@ -1001,9 +1055,9 @@ static const struct pci_device_id hpt37x[] = {
 };
 
 static struct pci_driver hpt37x_pci_driver = {
-       .name           = DRV_NAME,
+       .name           = DRV_NAME,
        .id_table       = hpt37x,
-       .probe          = hpt37x_init_one,
+       .probe          = hpt37x_init_one,
        .remove         = ata_pci_remove_one
 };
 
index 32f3463216b8df8b095b6af3dcc79c7142dbfda3..d2239bbdb798faba32b70f2a122ee1222052d8e8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Libata driver for the highpoint 372N and 302N UDMA66 ATA controllers.
+ * Libata driver for the HighPoint 371N, 372N, and 302N UDMA66 ATA controllers.
  *
  * This driver is heavily based upon:
  *
@@ -8,7 +8,7 @@
  * Copyright (C) 1999-2003             Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001         Sun Microsystems, Inc.
  * Portions Copyright (C) 2003         Red Hat Inc
- * Portions Copyright (C) 2005-2009    MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2010    MontaVista Software, Inc.
  *
  *
  * TODO
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt3x2n"
-#define DRV_VERSION    "0.3.10"
+#define DRV_VERSION    "0.3.13"
 
 enum {
        HPT_PCI_FAST    =       (1 << 31),
@@ -103,7 +103,7 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
 {
        struct hpt_clock *clocks = hpt3x2n_clocks;
 
-       while(clocks->xfer_speed) {
+       while (clocks->xfer_speed) {
                if (clocks->xfer_speed == speed)
                        return clocks->timing;
                clocks++;
@@ -112,6 +112,22 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
        return 0xffffffffU;     /* silence compiler warning */
 }
 
+/**
+ *     hpt372n_filter  -       mode selection filter
+ *     @adev: ATA device
+ *     @mask: mode mask
+ *
+ *     The Marvell bridge chips used on the HighPoint SATA cards do not seem
+ *     to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
+ */
+static unsigned long hpt372n_filter(struct ata_device *adev, unsigned long mask)
+{
+       if (ata_id_is_sata(adev->id))
+               mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA);
+
+       return mask;
+}
+
 /**
  *     hpt3x2n_cable_detect    -       Detect the cable type
  *     @ap: ATA port to detect on
@@ -153,6 +169,7 @@ static int hpt3x2n_pre_reset(struct ata_link *link, unsigned long deadline)
 {
        struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
        /* Reset the state machine */
        pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
        udelay(100);
@@ -328,10 +345,10 @@ static struct scsi_host_template hpt3x2n_sht = {
 };
 
 /*
- *     Configuration for HPT3x2n.
+ *     Configuration for HPT302N/371N.
  */
 
-static struct ata_port_operations hpt3x2n_port_ops = {
+static struct ata_port_operations hpt3xxn_port_ops = {
        .inherits       = &ata_bmdma_port_ops,
 
        .bmdma_stop     = hpt3x2n_bmdma_stop,
@@ -345,6 +362,15 @@ static struct ata_port_operations hpt3x2n_port_ops = {
        .prereset       = hpt3x2n_pre_reset,
 };
 
+/*
+ *     Configuration for HPT372N. Same as 302N/371N but we have a mode filter.
+ */
+
+static struct ata_port_operations hpt372n_port_ops = {
+       .inherits       = &hpt3xxn_port_ops,
+       .mode_filter    = &hpt372n_filter,
+};
+
 /**
  *     hpt3xn_calibrate_dpll           -       Calibrate the DPLL loop
  *     @dev: PCI device
@@ -359,12 +385,12 @@ static int hpt3xn_calibrate_dpll(struct pci_dev *dev)
        u32 reg5c;
        int tries;
 
-       for(tries = 0; tries < 0x5000; tries++) {
+       for (tries = 0; tries < 0x5000; tries++) {
                udelay(50);
                pci_read_config_byte(dev, 0x5b, &reg5b);
                if (reg5b & 0x80) {
                        /* See if it stays set */
-                       for(tries = 0; tries < 0x1000; tries ++) {
+                       for (tries = 0; tries < 0x1000; tries++) {
                                pci_read_config_byte(dev, 0x5b, &reg5b);
                                /* Failed ? */
                                if ((reg5b & 0x80) == 0)
@@ -372,7 +398,7 @@ static int hpt3xn_calibrate_dpll(struct pci_dev *dev)
                        }
                        /* Turn off tuning, we have the DPLL set */
                        pci_read_config_dword(dev, 0x5c, &reg5c);
-                       pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
+                       pci_write_config_dword(dev, 0x5c, reg5c & ~0x100);
                        return 1;
                }
        }
@@ -388,8 +414,19 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
 
        fcnt = inl(iobase + 0x90);      /* Not PCI readable for some chips */
        if ((fcnt >> 12) != 0xABCDE) {
-               printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n");
-               return 33;      /* Not BIOS set */
+               int i;
+               u16 sr;
+               u32 total = 0;
+
+               printk(KERN_WARNING "pata_hpt3x2n: BIOS clock data not set.\n");
+
+               /* This is the process the HPT371 BIOS is reported to use */
+               for (i = 0; i < 128; i++) {
+                       pci_read_config_word(pdev, 0x78, &sr);
+                       total += sr & 0x1FF;
+                       udelay(15);
+               }
+               fcnt = total / 128;
        }
        fcnt &= 0x1FF;
 
@@ -431,21 +468,27 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
  *     HPT372N                 9 (HPT372N)     *       UDMA133
  *
  *     (1) UDMA133 support depends on the bus clock
- *
- *     To pin down             HPT371N
  */
 
 static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       /* HPT372N and friends - UDMA133 */
-       static const struct ata_port_info info = {
+       /* HPT372N - UDMA133 */
+       static const struct ata_port_info info_hpt372n = {
+               .flags = ATA_FLAG_SLAVE_POSS,
+               .pio_mask = ATA_PIO4,
+               .mwdma_mask = ATA_MWDMA2,
+               .udma_mask = ATA_UDMA6,
+               .port_ops = &hpt372n_port_ops
+       };
+       /* HPT302N and HPT371N - UDMA133 */
+       static const struct ata_port_info info_hpt3xxn = {
                .flags = ATA_FLAG_SLAVE_POSS,
                .pio_mask = ATA_PIO4,
                .mwdma_mask = ATA_MWDMA2,
                .udma_mask = ATA_UDMA6,
-               .port_ops = &hpt3x2n_port_ops
+               .port_ops = &hpt3xxn_port_ops
        };
-       const struct ata_port_info *ppi[] = { &info, NULL };
+       const struct ata_port_info *ppi[] = { &info_hpt3xxn, NULL };
        u8 rev = dev->revision;
        u8 irqmask;
        unsigned int pci_mhz;
@@ -459,30 +502,36 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (rc)
                return rc;
 
-       switch(dev->device) {
-               case PCI_DEVICE_ID_TTI_HPT366:
-                       if (rev < 6)
-                               return -ENODEV;
-                       break;
-               case PCI_DEVICE_ID_TTI_HPT371:
-                       if (rev < 2)
-                               return -ENODEV;
-                       /* 371N if rev > 1 */
-                       break;
-               case PCI_DEVICE_ID_TTI_HPT372:
-                       /* 372N if rev >= 2*/
-                       if (rev < 2)
-                               return -ENODEV;
-                       break;
-               case PCI_DEVICE_ID_TTI_HPT302:
-                       if (rev < 2)
-                               return -ENODEV;
-                       break;
-               case PCI_DEVICE_ID_TTI_HPT372N:
-                       break;
-               default:
-                       printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device);
+       switch (dev->device) {
+       case PCI_DEVICE_ID_TTI_HPT366:
+               /* 372N if rev >= 6 */
+               if (rev < 6)
                        return -ENODEV;
+               goto hpt372n;
+       case PCI_DEVICE_ID_TTI_HPT371:
+               /* 371N if rev >= 2 */
+               if (rev < 2)
+                       return -ENODEV;
+               break;
+       case PCI_DEVICE_ID_TTI_HPT372:
+               /* 372N if rev >= 2 */
+               if (rev < 2)
+                       return -ENODEV;
+               goto hpt372n;
+       case PCI_DEVICE_ID_TTI_HPT302:
+               /* 302N if rev >= 2 */
+               if (rev < 2)
+                       return -ENODEV;
+               break;
+       case PCI_DEVICE_ID_TTI_HPT372N:
+hpt372n:
+               ppi[0] = &info_hpt372n;
+               break;
+       default:
+               printk(KERN_ERR
+                      "pata_hpt3x2n: PCI table is bogus please report (%d).\n",
+                      dev->device);
+               return -ENODEV;
        }
 
        /* Ok so this is a chip we support */
@@ -509,8 +558,10 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                pci_write_config_byte(dev, 0x50, mcr1);
        }
 
-       /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
-          50 for UDMA100. Right now we always use 66 */
+       /*
+        * Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
+        * 50 for UDMA100. Right now we always use 66
+        */
 
        pci_mhz = hpt3x2n_pci_clock(dev);
 
@@ -522,7 +573,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        pci_write_config_byte(dev, 0x5B, 0x21);
 
        /* Unlike the 37x we don't try jiggling the frequency */
-       for(adjust = 0; adjust < 8; adjust++) {
+       for (adjust = 0; adjust < 8; adjust++) {
                if (hpt3xn_calibrate_dpll(dev))
                        break;
                pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
@@ -534,8 +585,11 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
        printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using 66MHz DPLL.\n",
               pci_mhz);
-       /* Set our private data up. We only need a few flags so we use
-          it directly */
+
+       /*
+        * Set our private data up. We only need a few flags
+        * so we use it directly.
+        */
        if (pci_mhz > 60)
                hpriv = (void *)(PCI66 | USE_DPLL);
 
@@ -562,9 +616,9 @@ static const struct pci_device_id hpt3x2n[] = {
 };
 
 static struct pci_driver hpt3x2n_pci_driver = {
-       .name           = DRV_NAME,
+       .name           = DRV_NAME,
        .id_table       = hpt3x2n,
-       .probe          = hpt3x2n_init_one,
+       .probe          = hpt3x2n_init_one,
        .remove         = ata_pci_remove_one
 };
 
@@ -579,7 +633,7 @@ static void __exit hpt3x2n_exit(void)
 }
 
 MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3xxN");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, hpt3x2n);
 MODULE_VERSION(DRV_VERSION);
index 6ed645411c40d4bd7c59d33a9055da24e7ff1159..7613592615896d40715831fe2ae436ecf1db1cdd 100644 (file)
@@ -338,6 +338,35 @@ static void device_remove_attributes(struct device *dev,
                        device_remove_file(dev, &attrs[i]);
 }
 
+static int device_add_bin_attributes(struct device *dev,
+                                    struct bin_attribute *attrs)
+{
+       int error = 0;
+       int i;
+
+       if (attrs) {
+               for (i = 0; attr_name(attrs[i]); i++) {
+                       error = device_create_bin_file(dev, &attrs[i]);
+                       if (error)
+                               break;
+               }
+               if (error)
+                       while (--i >= 0)
+                               device_remove_bin_file(dev, &attrs[i]);
+       }
+       return error;
+}
+
+static void device_remove_bin_attributes(struct device *dev,
+                                        struct bin_attribute *attrs)
+{
+       int i;
+
+       if (attrs)
+               for (i = 0; attr_name(attrs[i]); i++)
+                       device_remove_bin_file(dev, &attrs[i]);
+}
+
 static int device_add_groups(struct device *dev,
                             const struct attribute_group **groups)
 {
@@ -378,12 +407,15 @@ static int device_add_attrs(struct device *dev)
                error = device_add_attributes(dev, class->dev_attrs);
                if (error)
                        return error;
+               error = device_add_bin_attributes(dev, class->dev_bin_attrs);
+               if (error)
+                       goto err_remove_class_attrs;
        }
 
        if (type) {
                error = device_add_groups(dev, type->groups);
                if (error)
-                       goto err_remove_class_attrs;
+                       goto err_remove_class_bin_attrs;
        }
 
        error = device_add_groups(dev, dev->groups);
@@ -395,6 +427,9 @@ static int device_add_attrs(struct device *dev)
  err_remove_type_groups:
        if (type)
                device_remove_groups(dev, type->groups);
+ err_remove_class_bin_attrs:
+       if (class)
+               device_remove_bin_attributes(dev, class->dev_bin_attrs);
  err_remove_class_attrs:
        if (class)
                device_remove_attributes(dev, class->dev_attrs);
@@ -412,8 +447,10 @@ static void device_remove_attrs(struct device *dev)
        if (type)
                device_remove_groups(dev, type->groups);
 
-       if (class)
+       if (class) {
                device_remove_attributes(dev, class->dev_attrs);
+               device_remove_bin_attributes(dev, class->dev_bin_attrs);
+       }
 }
 
 
index 81f2c84697f450544f3dfef66b1726cdfac83728..42f97f925629b7422080e2453a1d02b24d033f5b 100644 (file)
@@ -39,7 +39,7 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_idle);
  *
  * If PM operations are defined for the @dev's driver and they include
  * ->runtime_suspend(), execute it and return its error code.  Otherwise,
- * return -EINVAL.
+ * return 0.
  */
 int pm_generic_runtime_suspend(struct device *dev)
 {
@@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend);
  *
  * If PM operations are defined for the @dev's driver and they include
  * ->runtime_resume(), execute it and return its error code.  Otherwise,
- * return -EINVAL.
+ * return 0.
  */
 int pm_generic_runtime_resume(struct device *dev)
 {
@@ -185,7 +185,7 @@ static int __pm_generic_resume(struct device *dev, int event)
                return 0;
 
        ret = callback(dev);
-       if (!ret) {
+       if (!ret && pm_runtime_enabled(dev)) {
                pm_runtime_disable(dev);
                pm_runtime_set_active(dev);
                pm_runtime_enable(dev);
index ead3e79d6fcf10f684f8d8f55a30d7254356ff42..2a52270aeb305b2d9d7dc533f8e15a0f06b110b0 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/async.h>
+#include <linux/suspend.h>
 
 #include "../base.h"
 #include "power.h"
  */
 
 LIST_HEAD(dpm_list);
+LIST_HEAD(dpm_prepared_list);
+LIST_HEAD(dpm_suspended_list);
+LIST_HEAD(dpm_noirq_list);
 
 static DEFINE_MUTEX(dpm_list_mtx);
 static pm_message_t pm_transition;
 
-/*
- * Set once the preparation of devices for a PM transition has started, reset
- * before starting to resume devices.  Protected by dpm_list_mtx.
- */
-static bool transition_started;
-
 static int async_error;
 
 /**
@@ -59,7 +57,7 @@ static int async_error;
  */
 void device_pm_init(struct device *dev)
 {
-       dev->power.status = DPM_ON;
+       dev->power.in_suspend = false;
        init_completion(&dev->power.completion);
        complete_all(&dev->power.completion);
        dev->power.wakeup = NULL;
@@ -90,22 +88,11 @@ void device_pm_unlock(void)
 void device_pm_add(struct device *dev)
 {
        pr_debug("PM: Adding info for %s:%s\n",
-                dev->bus ? dev->bus->name : "No Bus",
-                kobject_name(&dev->kobj));
+                dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
        mutex_lock(&dpm_list_mtx);
-       if (dev->parent) {
-               if (dev->parent->power.status >= DPM_SUSPENDING)
-                       dev_warn(dev, "parent %s should not be sleeping\n",
-                                dev_name(dev->parent));
-       } else if (transition_started) {
-               /*
-                * We refuse to register parentless devices while a PM
-                * transition is in progress in order to avoid leaving them
-                * unhandled down the road
-                */
-               dev_WARN(dev, "Parentless device registered during a PM transaction\n");
-       }
-
+       if (dev->parent && dev->parent->power.in_suspend)
+               dev_warn(dev, "parent %s should not be sleeping\n",
+                       dev_name(dev->parent));
        list_add_tail(&dev->power.entry, &dpm_list);
        mutex_unlock(&dpm_list_mtx);
 }
@@ -117,8 +104,7 @@ void device_pm_add(struct device *dev)
 void device_pm_remove(struct device *dev)
 {
        pr_debug("PM: Removing info for %s:%s\n",
-                dev->bus ? dev->bus->name : "No Bus",
-                kobject_name(&dev->kobj));
+                dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
        complete_all(&dev->power.completion);
        mutex_lock(&dpm_list_mtx);
        list_del_init(&dev->power.entry);
@@ -135,10 +121,8 @@ void device_pm_remove(struct device *dev)
 void device_pm_move_before(struct device *deva, struct device *devb)
 {
        pr_debug("PM: Moving %s:%s before %s:%s\n",
-                deva->bus ? deva->bus->name : "No Bus",
-                kobject_name(&deva->kobj),
-                devb->bus ? devb->bus->name : "No Bus",
-                kobject_name(&devb->kobj));
+                deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
+                devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
        /* Delete deva from dpm_list and reinsert before devb. */
        list_move_tail(&deva->power.entry, &devb->power.entry);
 }
@@ -151,10 +135,8 @@ void device_pm_move_before(struct device *deva, struct device *devb)
 void device_pm_move_after(struct device *deva, struct device *devb)
 {
        pr_debug("PM: Moving %s:%s after %s:%s\n",
-                deva->bus ? deva->bus->name : "No Bus",
-                kobject_name(&deva->kobj),
-                devb->bus ? devb->bus->name : "No Bus",
-                kobject_name(&devb->kobj));
+                deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
+                devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
        /* Delete deva from dpm_list and reinsert after devb. */
        list_move(&deva->power.entry, &devb->power.entry);
 }
@@ -166,8 +148,7 @@ void device_pm_move_after(struct device *deva, struct device *devb)
 void device_pm_move_last(struct device *dev)
 {
        pr_debug("PM: Moving %s:%s to end of list\n",
-                dev->bus ? dev->bus->name : "No Bus",
-                kobject_name(&dev->kobj));
+                dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
        list_move_tail(&dev->power.entry, &dpm_list);
 }
 
@@ -303,7 +284,7 @@ static int pm_noirq_op(struct device *dev,
                        pm_message_t state)
 {
        int error = 0;
-       ktime_t calltime, delta, rettime;
+       ktime_t calltime = ktime_set(0, 0), delta, rettime;
 
        if (initcall_debug) {
                pr_info("calling  %s+ @ %i, parent: %s\n",
@@ -405,7 +386,7 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
                        int error)
 {
        printk(KERN_ERR "PM: Device %s failed to %s%s: error %d\n",
-               kobject_name(&dev->kobj), pm_verb(state.event), info, error);
+               dev_name(dev), pm_verb(state.event), info, error);
 }
 
 static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
@@ -475,33 +456,24 @@ End:
  */
 void dpm_resume_noirq(pm_message_t state)
 {
-       struct list_head list;
        ktime_t starttime = ktime_get();
 
-       INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
-       transition_started = false;
-       while (!list_empty(&dpm_list)) {
-               struct device *dev = to_device(dpm_list.next);
+       while (!list_empty(&dpm_noirq_list)) {
+               struct device *dev = to_device(dpm_noirq_list.next);
+               int error;
 
                get_device(dev);
-               if (dev->power.status > DPM_OFF) {
-                       int error;
-
-                       dev->power.status = DPM_OFF;
-                       mutex_unlock(&dpm_list_mtx);
+               list_move_tail(&dev->power.entry, &dpm_suspended_list);
+               mutex_unlock(&dpm_list_mtx);
 
-                       error = device_resume_noirq(dev, state);
+               error = device_resume_noirq(dev, state);
+               if (error)
+                       pm_dev_err(dev, state, " early", error);
 
-                       mutex_lock(&dpm_list_mtx);
-                       if (error)
-                               pm_dev_err(dev, state, " early", error);
-               }
-               if (!list_empty(&dev->power.entry))
-                       list_move_tail(&dev->power.entry, &list);
+               mutex_lock(&dpm_list_mtx);
                put_device(dev);
        }
-       list_splice(&list, &dpm_list);
        mutex_unlock(&dpm_list_mtx);
        dpm_show_time(starttime, state, "early");
        resume_device_irqs();
@@ -544,7 +516,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
        dpm_wait(dev->parent, async);
        device_lock(dev);
 
-       dev->power.status = DPM_RESUMING;
+       dev->power.in_suspend = false;
 
        if (dev->bus) {
                if (dev->bus->pm) {
@@ -610,19 +582,14 @@ static bool is_async(struct device *dev)
  */
 static void dpm_resume(pm_message_t state)
 {
-       struct list_head list;
        struct device *dev;
        ktime_t starttime = ktime_get();
 
-       INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
        pm_transition = state;
        async_error = 0;
 
-       list_for_each_entry(dev, &dpm_list, power.entry) {
-               if (dev->power.status < DPM_OFF)
-                       continue;
-
+       list_for_each_entry(dev, &dpm_suspended_list, power.entry) {
                INIT_COMPLETION(dev->power.completion);
                if (is_async(dev)) {
                        get_device(dev);
@@ -630,28 +597,24 @@ static void dpm_resume(pm_message_t state)
                }
        }
 
-       while (!list_empty(&dpm_list)) {
-               dev = to_device(dpm_list.next);
+       while (!list_empty(&dpm_suspended_list)) {
+               dev = to_device(dpm_suspended_list.next);
                get_device(dev);
-               if (dev->power.status >= DPM_OFF && !is_async(dev)) {
+               if (!is_async(dev)) {
                        int error;
 
                        mutex_unlock(&dpm_list_mtx);
 
                        error = device_resume(dev, state, false);
-
-                       mutex_lock(&dpm_list_mtx);
                        if (error)
                                pm_dev_err(dev, state, "", error);
-               } else if (dev->power.status == DPM_SUSPENDING) {
-                       /* Allow new children of the device to be registered */
-                       dev->power.status = DPM_RESUMING;
+
+                       mutex_lock(&dpm_list_mtx);
                }
                if (!list_empty(&dev->power.entry))
-                       list_move_tail(&dev->power.entry, &list);
+                       list_move_tail(&dev->power.entry, &dpm_prepared_list);
                put_device(dev);
        }
-       list_splice(&list, &dpm_list);
        mutex_unlock(&dpm_list_mtx);
        async_synchronize_full();
        dpm_show_time(starttime, state, NULL);
@@ -697,22 +660,18 @@ static void dpm_complete(pm_message_t state)
 
        INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
-       transition_started = false;
-       while (!list_empty(&dpm_list)) {
-               struct device *dev = to_device(dpm_list.prev);
+       while (!list_empty(&dpm_prepared_list)) {
+               struct device *dev = to_device(dpm_prepared_list.prev);
 
                get_device(dev);
-               if (dev->power.status > DPM_ON) {
-                       dev->power.status = DPM_ON;
-                       mutex_unlock(&dpm_list_mtx);
+               dev->power.in_suspend = false;
+               list_move(&dev->power.entry, &list);
+               mutex_unlock(&dpm_list_mtx);
 
-                       device_complete(dev, state);
-                       pm_runtime_put_sync(dev);
+               device_complete(dev, state);
+               pm_runtime_put_sync(dev);
 
-                       mutex_lock(&dpm_list_mtx);
-               }
-               if (!list_empty(&dev->power.entry))
-                       list_move(&dev->power.entry, &list);
+               mutex_lock(&dpm_list_mtx);
                put_device(dev);
        }
        list_splice(&list, &dpm_list);
@@ -802,15 +761,13 @@ End:
  */
 int dpm_suspend_noirq(pm_message_t state)
 {
-       struct list_head list;
        ktime_t starttime = ktime_get();
        int error = 0;
 
-       INIT_LIST_HEAD(&list);
        suspend_device_irqs();
        mutex_lock(&dpm_list_mtx);
-       while (!list_empty(&dpm_list)) {
-               struct device *dev = to_device(dpm_list.prev);
+       while (!list_empty(&dpm_suspended_list)) {
+               struct device *dev = to_device(dpm_suspended_list.prev);
 
                get_device(dev);
                mutex_unlock(&dpm_list_mtx);
@@ -823,12 +780,10 @@ int dpm_suspend_noirq(pm_message_t state)
                        put_device(dev);
                        break;
                }
-               dev->power.status = DPM_OFF_IRQ;
                if (!list_empty(&dev->power.entry))
-                       list_move(&dev->power.entry, &list);
+                       list_move(&dev->power.entry, &dpm_noirq_list);
                put_device(dev);
        }
-       list_splice_tail(&list, &dpm_list);
        mutex_unlock(&dpm_list_mtx);
        if (error)
                dpm_resume_noirq(resume_event(state));
@@ -876,6 +831,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
        if (async_error)
                goto End;
 
+       if (pm_wakeup_pending()) {
+               async_error = -EBUSY;
+               goto End;
+       }
+
        if (dev->class) {
                if (dev->class->pm) {
                        pm_dev_dbg(dev, state, "class ");
@@ -907,9 +867,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                }
        }
 
-       if (!error)
-               dev->power.status = DPM_OFF;
-
  End:
        device_unlock(dev);
        complete_all(&dev->power.completion);
@@ -951,16 +908,14 @@ static int device_suspend(struct device *dev)
  */
 static int dpm_suspend(pm_message_t state)
 {
-       struct list_head list;
        ktime_t starttime = ktime_get();
        int error = 0;
 
-       INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
        pm_transition = state;
        async_error = 0;
-       while (!list_empty(&dpm_list)) {
-               struct device *dev = to_device(dpm_list.prev);
+       while (!list_empty(&dpm_prepared_list)) {
+               struct device *dev = to_device(dpm_prepared_list.prev);
 
                get_device(dev);
                mutex_unlock(&dpm_list_mtx);
@@ -974,12 +929,11 @@ static int dpm_suspend(pm_message_t state)
                        break;
                }
                if (!list_empty(&dev->power.entry))
-                       list_move(&dev->power.entry, &list);
+                       list_move(&dev->power.entry, &dpm_suspended_list);
                put_device(dev);
                if (async_error)
                        break;
        }
-       list_splice(&list, dpm_list.prev);
        mutex_unlock(&dpm_list_mtx);
        async_synchronize_full();
        if (!error)
@@ -1038,22 +992,20 @@ static int device_prepare(struct device *dev, pm_message_t state)
  */
 static int dpm_prepare(pm_message_t state)
 {
-       struct list_head list;
        int error = 0;
 
-       INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
-       transition_started = true;
        while (!list_empty(&dpm_list)) {
                struct device *dev = to_device(dpm_list.next);
 
                get_device(dev);
-               dev->power.status = DPM_PREPARING;
                mutex_unlock(&dpm_list_mtx);
 
                pm_runtime_get_noresume(dev);
-               if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) {
-                       /* Wake-up requested during system sleep transition. */
+               if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
+                       pm_wakeup_event(dev, 0);
+
+               if (pm_wakeup_pending()) {
                        pm_runtime_put_sync(dev);
                        error = -EBUSY;
                } else {
@@ -1062,24 +1014,22 @@ static int dpm_prepare(pm_message_t state)
 
                mutex_lock(&dpm_list_mtx);
                if (error) {
-                       dev->power.status = DPM_ON;
                        if (error == -EAGAIN) {
                                put_device(dev);
                                error = 0;
                                continue;
                        }
-                       printk(KERN_ERR "PM: Failed to prepare device %s "
-                               "for power transition: error %d\n",
-                               kobject_name(&dev->kobj), error);
+                       printk(KERN_INFO "PM: Device %s not prepared "
+                               "for power transition: code %d\n",
+                               dev_name(dev), error);
                        put_device(dev);
                        break;
                }
-               dev->power.status = DPM_SUSPENDING;
+               dev->power.in_suspend = true;
                if (!list_empty(&dev->power.entry))
-                       list_move_tail(&dev->power.entry, &list);
+                       list_move_tail(&dev->power.entry, &dpm_prepared_list);
                put_device(dev);
        }
-       list_splice(&list, &dpm_list);
        mutex_unlock(&dpm_list_mtx);
        return error;
 }
index 02c652be83e72ce09f5c1316cc3c8415a5894556..656493a5e073262dc88efc646d254abd5c3646c7 100644 (file)
@@ -250,13 +250,16 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
        if (!cb)
                return -ENOSYS;
 
-       spin_unlock_irq(&dev->power.lock);
+       if (dev->power.irq_safe) {
+               retval = cb(dev);
+       } else {
+               spin_unlock_irq(&dev->power.lock);
 
-       retval = cb(dev);
+               retval = cb(dev);
 
-       spin_lock_irq(&dev->power.lock);
+               spin_lock_irq(&dev->power.lock);
+       }
        dev->power.runtime_error = retval;
-
        return retval;
 }
 
@@ -404,7 +407,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                goto out;
        }
 
-       if (parent && !parent->power.ignore_children) {
+       if (parent && !parent->power.ignore_children && !dev->power.irq_safe) {
                spin_unlock_irq(&dev->power.lock);
 
                pm_request_idle(parent);
@@ -527,10 +530,13 @@ static int rpm_resume(struct device *dev, int rpmflags)
 
        if (!parent && dev->parent) {
                /*
-                * Increment the parent's resume counter and resume it if
-                * necessary.
+                * Increment the parent's usage counter and resume it if
+                * necessary.  Not needed if dev is irq-safe; then the
+                * parent is permanently resumed.
                 */
                parent = dev->parent;
+               if (dev->power.irq_safe)
+                       goto skip_parent;
                spin_unlock(&dev->power.lock);
 
                pm_runtime_get_noresume(parent);
@@ -553,6 +559,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
                        goto out;
                goto repeat;
        }
+ skip_parent:
 
        if (dev->power.no_callbacks)
                goto no_callback;       /* Assume success. */
@@ -584,7 +591,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
                rpm_idle(dev, RPM_ASYNC);
 
  out:
-       if (parent) {
+       if (parent && !dev->power.irq_safe) {
                spin_unlock_irq(&dev->power.lock);
 
                pm_runtime_put(parent);
@@ -1065,7 +1072,6 @@ EXPORT_SYMBOL_GPL(pm_runtime_allow);
  * Set the power.no_callbacks flag, which tells the PM core that this
  * device is power-managed through its parent and has no run-time PM
  * callbacks of its own.  The run-time sysfs attributes will be removed.
- *
  */
 void pm_runtime_no_callbacks(struct device *dev)
 {
@@ -1077,6 +1083,27 @@ void pm_runtime_no_callbacks(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);
 
+/**
+ * pm_runtime_irq_safe - Leave interrupts disabled during callbacks.
+ * @dev: Device to handle
+ *
+ * Set the power.irq_safe flag, which tells the PM core that the
+ * ->runtime_suspend() and ->runtime_resume() callbacks for this device should
+ * always be invoked with the spinlock held and interrupts disabled.  It also
+ * causes the parent's usage counter to be permanently incremented, preventing
+ * the parent from runtime suspending -- otherwise an irq-safe child might have
+ * to wait for a non-irq-safe parent.
+ */
+void pm_runtime_irq_safe(struct device *dev)
+{
+       if (dev->parent)
+               pm_runtime_get_sync(dev->parent);
+       spin_lock_irq(&dev->power.lock);
+       dev->power.irq_safe = 1;
+       spin_unlock_irq(&dev->power.lock);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_irq_safe);
+
 /**
  * update_autosuspend - Handle a change to a device's autosuspend settings.
  * @dev: Device to handle.
@@ -1199,4 +1226,6 @@ void pm_runtime_remove(struct device *dev)
        /* Change the status back to 'suspended' to match the initial status. */
        if (dev->power.runtime_status == RPM_ACTIVE)
                pm_runtime_set_suspended(dev);
+       if (dev->power.irq_safe && dev->parent)
+               pm_runtime_put_sync(dev->parent);
 }
index 71c5528e1c357a81112c6f79b1e91f013a58e3aa..8ec406d8f548eae6b84ed692236c12ee45139fa4 100644 (file)
@@ -542,26 +542,26 @@ static void pm_wakeup_update_hit_counts(void)
 }
 
 /**
- * pm_check_wakeup_events - Check for new wakeup events.
+ * pm_wakeup_pending - Check if power transition in progress should be aborted.
  *
  * Compare the current number of registered wakeup events with its preserved
- * value from the past to check if new wakeup events have been registered since
- * the old value was stored.  Check if the current number of wakeup events being
- * processed is zero.
+ * value from the past and return true if new wakeup events have been registered
+ * since the old value was stored.  Also return true if the current number of
+ * wakeup events being processed is different from zero.
  */
-bool pm_check_wakeup_events(void)
+bool pm_wakeup_pending(void)
 {
        unsigned long flags;
-       bool ret = true;
+       bool ret = false;
 
        spin_lock_irqsave(&events_lock, flags);
        if (events_check_enabled) {
-               ret = ((unsigned int)atomic_read(&event_count) == saved_count)
-                       && !atomic_read(&events_in_progress);
-               events_check_enabled = ret;
+               ret = ((unsigned int)atomic_read(&event_count) != saved_count)
+                       || atomic_read(&events_in_progress);
+               events_check_enabled = !ret;
        }
        spin_unlock_irqrestore(&events_lock, flags);
-       if (!ret)
+       if (ret)
                pm_wakeup_update_hit_counts();
        return ret;
 }
index 3951020e494ac803001083b186a5b7614eb6d42f..25e4dffa0aad6c373135c73841b5f55ad5082df9 100644 (file)
@@ -4352,7 +4352,7 @@ static int __init floppy_init(void)
 out_unreg_platform_dev:
        platform_device_unregister(&floppy_device[drive]);
 out_flush_work:
-       flush_scheduled_work();
+       flush_work_sync(&floppy_work);
        if (atomic_read(&usage_count))
                floppy_release_irq_and_dma();
 out_unreg_region:
@@ -4422,7 +4422,7 @@ static int floppy_grab_irq_and_dma(void)
         * We might have scheduled a free_irq(), wait it to
         * drain first:
         */
-       flush_scheduled_work();
+       flush_work_sync(&floppy_work);
 
        if (fd_request_irq()) {
                DPRINT("Unable to grab IRQ%d for the floppy driver\n",
index 657873e4328dbf05421b80e8d1231f27c5d3b369..d7aa39e349a617ac26bb253f5b7e329bead28656 100644 (file)
@@ -547,7 +547,7 @@ static void xlvbd_release_gendisk(struct blkfront_info *info)
        spin_unlock_irqrestore(&blkif_io_lock, flags);
 
        /* Flush gnttab callback work. Must be done with no locks held. */
-       flush_scheduled_work();
+       flush_work_sync(&info->work);
 
        del_gendisk(info->gd);
 
@@ -596,7 +596,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)
        spin_unlock_irq(&blkif_io_lock);
 
        /* Flush gnttab callback work. Must be done with no locks held. */
-       flush_scheduled_work();
+       flush_work_sync(&info->work);
 
        /* Free resources associated with old device channel. */
        if (info->ring_ref != GRANT_INVALID_REF) {
index de65915308fb2fad8b5ebe57aec835ebe69d4a66..64a21461c408f9853d6c6199bc1ed9e38fb842ca 100644 (file)
@@ -837,7 +837,7 @@ probe_fail_no_mem:
 
 static int __devexit remove_gdrom(struct platform_device *devptr)
 {
-       flush_scheduled_work();
+       flush_work_sync(&work);
        blk_cleanup_queue(gd.gdrom_rq);
        free_irq(HW_EVENT_GDROM_CMD, &gd);
        free_irq(HW_EVENT_GDROM_DMA, &gd);
index a2bc885ce60a8e2bab93a815ab6ffc7d86640220..67a75a502c01f54034c6c050b1be6ae3103fc75f 100644 (file)
@@ -850,8 +850,8 @@ static void hvsi_flush_output(struct hvsi_struct *hp)
        wait_event_timeout(hp->emptyq, (hp->n_outbuf <= 0), HVSI_TIMEOUT);
 
        /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */
-       cancel_delayed_work(&hp->writer);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&hp->writer);
+       flush_work_sync(&hp->handshaker);
 
        /*
         * it's also possible that our timeout expired and hvsi_write_worker
index 035da9e64a1704fce0d28e35cb74a5bdd8ef0593..f27c04e18aaaeabe30c9bbd1fe99fa71474fb947 100644 (file)
@@ -69,6 +69,8 @@
 #ifdef CONFIG_PPC_OF
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #endif
 
 #define PFX "ipmi_si: "
@@ -2546,7 +2548,7 @@ static int __devinit ipmi_of_probe(struct platform_device *dev,
 {
        struct smi_info *info;
        struct resource resource;
-       const int *regsize, *regspacing, *regshift;
+       const __be32 *regsize, *regspacing, *regshift;
        struct device_node *np = dev->dev.of_node;
        int ret;
        int proplen;
@@ -2599,9 +2601,9 @@ static int __devinit ipmi_of_probe(struct platform_device *dev,
 
        info->io.addr_data      = resource.start;
 
-       info->io.regsize        = regsize ? *regsize : DEFAULT_REGSIZE;
-       info->io.regspacing     = regspacing ? *regspacing : DEFAULT_REGSPACING;
-       info->io.regshift       = regshift ? *regshift : 0;
+       info->io.regsize        = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE;
+       info->io.regspacing     = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING;
+       info->io.regshift       = regshift ? be32_to_cpup(regshift) : 0;
 
        info->irq               = irq_of_parse_and_map(dev->dev.of_node, 0);
        info->dev               = &dev->dev;
index 99cffdab1056565c3e73276a3cf304a8224c5d8e..0aeb5a38d2963bcc6bc4e010b3c2376a788aa55b 100644 (file)
@@ -1729,7 +1729,7 @@ void ipwireless_hardware_free(struct ipw_hardware *hw)
 
        ipwireless_stop_interrupts(hw);
 
-       flush_scheduled_work();
+       flush_work_sync(&hw->work_rx);
 
        for (i = 0; i < NL_NUM_OF_ADDRESSES; i++)
                if (hw->packet_assembler[i] != NULL)
index 9fe538347932939a7caadce5fec586bee8103312..f7daeea598e43e12e02b0cceafd066c1690ad3d4 100644 (file)
@@ -430,7 +430,8 @@ void ipwireless_network_free(struct ipw_network *network)
        network->shutting_down = 1;
 
        ipwireless_ppp_close(network);
-       flush_scheduled_work();
+       flush_work_sync(&network->work_go_online);
+       flush_work_sync(&network->work_go_offline);
 
        ipwireless_stop_interrupts(network->hardware);
        ipwireless_associate_network(network->hardware, NULL);
index 1a2c2c3b068f08401ead84b00d1e6a63c6ff0728..f5eb28b6cb0f53da42c256d1f92f3832d9405af7 100644 (file)
@@ -577,7 +577,7 @@ void ipwireless_tty_free(struct ipw_tty *tty)
                                mutex_unlock(&ttyj->ipw_tty_mutex);
                                tty_hangup(ttyj->linux_tty);
                                /* Wait till the tty_hangup has completed */
-                               flush_scheduled_work();
+                               flush_work_sync(&ttyj->linux_tty->hangup_work);
                                /* FIXME: Exactly how is the tty object locked here
                                   against a parallel ioctl etc */
                                mutex_lock(&ttyj->ipw_tty_mutex);
index 5a1aa64f4e76c5b9178dbb9d3ef4fe9285ed8791..72a4fcb1774509a5e624cf4bc72805cb041e4d28 100644 (file)
@@ -626,7 +626,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
        preempt_disable();
        /* if over the trickle threshold, use only 1 in 4096 samples */
        if (input_pool.entropy_count > trickle_thresh &&
-           (__get_cpu_var(trickle_count)++ & 0xfff))
+           ((__this_cpu_inc_return(trickle_count) - 1) & 0xfff))
                goto out;
 
        sample.jiffies = jiffies;
index 4be62eda9fbc6ddac0522e8d321b7afd1bba015a..e8c52c882b210aa87b0f76ddaa2ac3e714eb1c53 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
-#include <linux/kobject.h>
 #include <linux/fs.h>
 #include <linux/cdev.h>
 #include <linux/semaphore.h>
index 73f66d03624dfd2b1e51a0aab8c236fc6ec4c7d6..79e36c878a4c181d2edc5e8f3e9b6b00b8fb4253 100644 (file)
@@ -1434,7 +1434,7 @@ static int __devexit sonypi_remove(struct platform_device *dev)
        sonypi_disable();
 
        synchronize_irq(sonypi_device.irq);
-       flush_scheduled_work();
+       flush_work_sync(&sonypi_device.input_work);
 
        if (useinput) {
                input_unregister_device(sonypi_device.input_key_dev);
index 7c4133582dbae484f449d49f97b2ee0f179a9891..1f46f1cd9225c3c0d2a894bc80d3d1e74fe012e7 100644 (file)
@@ -736,7 +736,7 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
        if (chip == NULL)
                return -ENODEV;
        rc = __tpm_pcr_read(chip, pcr_idx, res_buf);
-       module_put(chip->dev->driver->owner);
+       tpm_chip_put(chip);
        return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_pcr_read);
@@ -775,11 +775,27 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
        rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
                          "attempting extend a PCR value");
 
-       module_put(chip->dev->driver->owner);
+       tpm_chip_put(chip);
        return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_pcr_extend);
 
+int tpm_send(u32 chip_num, void *cmd, size_t buflen)
+{
+       struct tpm_chip *chip;
+       int rc;
+
+       chip = tpm_chip_find_get(chip_num);
+       if (chip == NULL)
+               return -ENODEV;
+
+       rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
+
+       tpm_chip_put(chip);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_send);
+
 ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
                      char *buf)
 {
@@ -986,7 +1002,7 @@ int tpm_release(struct inode *inode, struct file *file)
        struct tpm_chip *chip = file->private_data;
 
        del_singleshot_timer_sync(&chip->user_read_timer);
-       flush_scheduled_work();
+       flush_work_sync(&chip->work);
        file->private_data = NULL;
        atomic_set(&chip->data_pending, 0);
        kfree(chip->data_buffer);
@@ -1038,7 +1054,7 @@ ssize_t tpm_read(struct file *file, char __user *buf,
        ssize_t ret_size;
 
        del_singleshot_timer_sync(&chip->user_read_timer);
-       flush_scheduled_work();
+       flush_work_sync(&chip->work);
        ret_size = atomic_read(&chip->data_pending);
        atomic_set(&chip->data_pending, 0);
        if (ret_size > 0) {     /* relay data */
index 792868d24f2a0f2ad6bc21a4967ace01a2f84d92..72ddb031b69a24e425a22d5892283b91f6cc1eec 100644 (file)
@@ -113,6 +113,11 @@ struct tpm_chip {
 
 #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
 
+static inline void tpm_chip_put(struct tpm_chip *chip)
+{
+       module_put(chip->dev->driver->owner);
+}
+
 static inline int tpm_read_index(int base, int index)
 {
        outb(index, base);
index a7f046b0096ca26121a1016922fef359ee4d805c..2b46a7efa0ac78c5c4213609d7846422842ef17f 100644 (file)
@@ -43,9 +43,10 @@ static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 };
 
 static inline void get_seq(__u32 *ts, int *cpu)
 {
-       *ts = get_cpu_var(proc_event_counts)++;
+       preempt_disable();
+       *ts = __this_cpu_inc_return(proc_event_counts) -1;
        *cpu = smp_processor_id();
-       put_cpu_var(proc_event_counts);
+       preempt_enable();
 }
 
 void proc_fork_connector(struct task_struct *task)
index 08d5f05378d9efb1df0fe055240e8e8ed9e7a90b..386888f10df02c0147b1b3664d8b08e7ebe88aa4 100644 (file)
@@ -49,7 +49,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev);
  */
 static void cpuidle_idle_call(void)
 {
-       struct cpuidle_device *dev = __get_cpu_var(cpuidle_devices);
+       struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
        struct cpuidle_state *target_state;
        int next_state;
 
index 40a222e19b2d08c7d0bbdef96b0170cd483e444d..68f942cb30f26808e58b9004107e56dce21df2f9 100644 (file)
@@ -19,7 +19,7 @@ config FIREWIRE
 
 config FIREWIRE_OHCI
        tristate "OHCI-1394 controllers"
-       depends on PCI && FIREWIRE
+       depends on PCI && FIREWIRE && MMU
        help
          Enable this driver if you have a FireWire controller based
          on the OHCI specification.  For all practical purposes, this
index 14bb7b7b5dd7bda6e4d98b9066937212c70043d0..48ae712e21018e64cca840b3e146b728bda72f99 100644 (file)
@@ -1501,9 +1501,10 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
        e->client               = client;
        e->p.speed              = SCODE_100;
        e->p.generation         = a->generation;
-       e->p.header[0]          = a->data[0];
-       e->p.header[1]          = a->data[1];
-       e->p.header_length      = 8;
+       e->p.header[0]          = TCODE_LINK_INTERNAL << 4;
+       e->p.header[1]          = a->data[0];
+       e->p.header[2]          = a->data[1];
+       e->p.header_length      = 12;
        e->p.callback           = outbound_phy_packet_callback;
        e->phy_packet.closure   = a->closure;
        e->phy_packet.type      = FW_CDEV_EVENT_PHY_PACKET_SENT;
index b42a0bde8494bf0dec8cc2e20d34dfc3e7c046b5..d00f8ce902cc429914c31644a213531d6a239706 100644 (file)
 #define PHY_CONFIG_ROOT_ID(node_id)    ((((node_id) & 0x3f) << 24) | (1 << 23))
 #define PHY_IDENTIFIER(id)             ((id) << 30)
 
+/* returns 0 if the split timeout handler is already running */
+static int try_cancel_split_timeout(struct fw_transaction *t)
+{
+       if (t->is_split_transaction)
+               return del_timer(&t->split_timeout_timer);
+       else
+               return 1;
+}
+
 static int close_transaction(struct fw_transaction *transaction,
                             struct fw_card *card, int rcode)
 {
@@ -81,7 +90,7 @@ static int close_transaction(struct fw_transaction *transaction,
        spin_lock_irqsave(&card->lock, flags);
        list_for_each_entry(t, &card->transaction_list, link) {
                if (t == transaction) {
-                       if (!del_timer(&t->split_timeout_timer)) {
+                       if (!try_cancel_split_timeout(t)) {
                                spin_unlock_irqrestore(&card->lock, flags);
                                goto timed_out;
                        }
@@ -141,16 +150,28 @@ static void split_transaction_timeout_callback(unsigned long data)
        card->tlabel_mask &= ~(1ULL << t->tlabel);
        spin_unlock_irqrestore(&card->lock, flags);
 
-       card->driver->cancel_packet(card, &t->packet);
-
-       /*
-        * At this point cancel_packet will never call the transaction
-        * callback, since we just took the transaction out of the list.
-        * So do it here.
-        */
        t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
 }
 
+static void start_split_transaction_timeout(struct fw_transaction *t,
+                                           struct fw_card *card)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+
+       if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) {
+               spin_unlock_irqrestore(&card->lock, flags);
+               return;
+       }
+
+       t->is_split_transaction = true;
+       mod_timer(&t->split_timeout_timer,
+                 jiffies + card->split_timeout_jiffies);
+
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
 static void transmit_complete_callback(struct fw_packet *packet,
                                       struct fw_card *card, int status)
 {
@@ -162,7 +183,7 @@ static void transmit_complete_callback(struct fw_packet *packet,
                close_transaction(t, card, RCODE_COMPLETE);
                break;
        case ACK_PENDING:
-               t->timestamp = packet->timestamp;
+               start_split_transaction_timeout(t, card);
                break;
        case ACK_BUSY_X:
        case ACK_BUSY_A:
@@ -250,7 +271,7 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
                break;
 
        default:
-               WARN(1, "wrong tcode %d", tcode);
+               WARN(1, "wrong tcode %d\n", tcode);
        }
  common:
        packet->speed = speed;
@@ -349,11 +370,9 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
        t->node_id = destination_id;
        t->tlabel = tlabel;
        t->card = card;
+       t->is_split_transaction = false;
        setup_timer(&t->split_timeout_timer,
                    split_transaction_timeout_callback, (unsigned long)t);
-       /* FIXME: start this timer later, relative to t->timestamp */
-       mod_timer(&t->split_timeout_timer,
-                 jiffies + card->split_timeout_jiffies);
        t->callback = callback;
        t->callback_data = callback_data;
 
@@ -423,7 +442,8 @@ static void transmit_phy_packet_callback(struct fw_packet *packet,
 }
 
 static struct fw_packet phy_config_packet = {
-       .header_length  = 8,
+       .header_length  = 12,
+       .header[0]      = TCODE_LINK_INTERNAL << 4,
        .payload_length = 0,
        .speed          = SCODE_100,
        .callback       = transmit_phy_packet_callback,
@@ -451,8 +471,8 @@ void fw_send_phy_config(struct fw_card *card,
 
        mutex_lock(&phy_config_mutex);
 
-       phy_config_packet.header[0] = data;
-       phy_config_packet.header[1] = ~data;
+       phy_config_packet.header[1] = data;
+       phy_config_packet.header[2] = ~data;
        phy_config_packet.generation = generation;
        INIT_COMPLETION(phy_config_done);
 
@@ -638,7 +658,7 @@ int fw_get_response_length(struct fw_request *r)
                }
 
        default:
-               WARN(1, "wrong tcode %d", tcode);
+               WARN(1, "wrong tcode %d\n", tcode);
                return 0;
        }
 }
@@ -694,7 +714,7 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
                break;
 
        default:
-               WARN(1, "wrong tcode %d", tcode);
+               WARN(1, "wrong tcode %d\n", tcode);
        }
 
        response->payload_mapped = false;
@@ -925,7 +945,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
        spin_lock_irqsave(&card->lock, flags);
        list_for_each_entry(t, &card->transaction_list, link) {
                if (t->node_id == source && t->tlabel == tlabel) {
-                       if (!del_timer(&t->split_timeout_timer)) {
+                       if (!try_cancel_split_timeout(t)) {
                                spin_unlock_irqrestore(&card->lock, flags);
                                goto timed_out;
                        }
index e6239f971be62f425bce4a859dcedb2d05921d8c..f8dfcf1c6cbebe913b7fbef7a24f1da3d5e00dad 100644 (file)
@@ -215,9 +215,11 @@ static inline bool is_next_generation(int new_generation, int old_generation)
 
 /* -transaction */
 
+#define TCODE_LINK_INTERNAL            0xe
+
 #define TCODE_IS_READ_REQUEST(tcode)   (((tcode) & ~1) == 4)
 #define TCODE_IS_BLOCK_PACKET(tcode)   (((tcode) &  1) != 0)
-#define TCODE_IS_LINK_INTERNAL(tcode)  ((tcode) == 0xe)
+#define TCODE_IS_LINK_INTERNAL(tcode)  ((tcode) == TCODE_LINK_INTERNAL)
 #define TCODE_IS_REQUEST(tcode)                (((tcode) &  2) == 0)
 #define TCODE_IS_RESPONSE(tcode)       (((tcode) &  2) != 0)
 #define TCODE_HAS_REQUEST_DATA(tcode)  (((tcode) & 12) != 4)
index 1a467a91fb0b2c8ee4c7ac577f02c497d249e1dc..c2e194c5866717633d426636cc5cd5e43efa821e 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/bug.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/ethtool.h>
 #include <linux/firewire.h>
 #include <linux/firewire-constants.h>
 #include <linux/highmem.h>
@@ -179,6 +180,7 @@ struct fwnet_device {
        /* Number of tx datagrams that have been queued but not yet acked */
        int queued_datagrams;
 
+       int peer_count;
        struct list_head peer_list;
        struct fw_card *card;
        struct net_device *netdev;
@@ -996,15 +998,23 @@ static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask)
 static void fwnet_write_complete(struct fw_card *card, int rcode,
                                 void *payload, size_t length, void *data)
 {
-       struct fwnet_packet_task *ptask;
-
-       ptask = data;
+       struct fwnet_packet_task *ptask = data;
+       static unsigned long j;
+       static int last_rcode, errors_skipped;
 
        if (rcode == RCODE_COMPLETE) {
                fwnet_transmit_packet_done(ptask);
        } else {
-               fw_error("fwnet_write_complete: failed: %x\n", rcode);
                fwnet_transmit_packet_failed(ptask);
+
+               if (printk_timed_ratelimit(&j,  1000) || rcode != last_rcode) {
+                       fw_error("fwnet_write_complete: "
+                               "failed: %x (skipped %d)\n", rcode, errors_skipped);
+
+                       errors_skipped = 0;
+                       last_rcode = rcode;
+               } else
+                       errors_skipped++;
        }
 }
 
@@ -1213,6 +1223,14 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)
        return retval;
 }
 
+static void set_carrier_state(struct fwnet_device *dev)
+{
+       if (dev->peer_count > 1)
+               netif_carrier_on(dev->netdev);
+       else
+               netif_carrier_off(dev->netdev);
+}
+
 /* ifup */
 static int fwnet_open(struct net_device *net)
 {
@@ -1226,6 +1244,10 @@ static int fwnet_open(struct net_device *net)
        }
        netif_start_queue(net);
 
+       spin_lock_irq(&dev->lock);
+       set_carrier_state(dev);
+       spin_unlock_irq(&dev->lock);
+
        return 0;
 }
 
@@ -1397,6 +1419,10 @@ static int fwnet_change_mtu(struct net_device *net, int new_mtu)
        return 0;
 }
 
+static const struct ethtool_ops fwnet_ethtool_ops = {
+       .get_link       = ethtool_op_get_link,
+};
+
 static const struct net_device_ops fwnet_netdev_ops = {
        .ndo_open       = fwnet_open,
        .ndo_stop       = fwnet_stop,
@@ -1415,6 +1441,7 @@ static void fwnet_init_dev(struct net_device *net)
        net->hard_header_len    = FWNET_HLEN;
        net->type               = ARPHRD_IEEE1394;
        net->tx_queue_len       = FWNET_TX_QUEUE_LEN;
+       net->ethtool_ops        = &fwnet_ethtool_ops;
 }
 
 /* caller must hold fwnet_device_mutex */
@@ -1455,6 +1482,8 @@ static int fwnet_add_peer(struct fwnet_device *dev,
 
        spin_lock_irq(&dev->lock);
        list_add_tail(&peer->peer_link, &dev->peer_list);
+       dev->peer_count++;
+       set_carrier_state(dev);
        spin_unlock_irq(&dev->lock);
 
        return 0;
@@ -1535,13 +1564,15 @@ static int fwnet_probe(struct device *_dev)
        return ret;
 }
 
-static void fwnet_remove_peer(struct fwnet_peer *peer)
+static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev)
 {
        struct fwnet_partial_datagram *pd, *pd_next;
 
-       spin_lock_irq(&peer->dev->lock);
+       spin_lock_irq(&dev->lock);
        list_del(&peer->peer_link);
-       spin_unlock_irq(&peer->dev->lock);
+       dev->peer_count--;
+       set_carrier_state(dev);
+       spin_unlock_irq(&dev->lock);
 
        list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link)
                fwnet_pd_delete(pd);
@@ -1558,7 +1589,7 @@ static int fwnet_remove(struct device *_dev)
 
        mutex_lock(&fwnet_device_mutex);
 
-       fwnet_remove_peer(peer);
+       fwnet_remove_peer(peer, dev);
 
        if (list_empty(&dev->peer_list)) {
                net = dev->netdev;
index bf184fb59a5e4329ca11a391cefdc011ea050dfd..0618145376ade6b4608cd16792408f6e2b94ee23 100644 (file)
@@ -302,7 +302,7 @@ nosy_open(struct inode *inode, struct file *file)
 
        file->private_data = client;
 
-       return 0;
+       return nonseekable_open(inode, file);
 fail:
        kfree(client);
        lynx_put(lynx);
@@ -405,7 +405,6 @@ static const struct file_operations nosy_ops = {
        .poll =                 nosy_poll,
        .open =                 nosy_open,
        .release =              nosy_release,
-       .llseek =               noop_llseek,
 };
 
 #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */
index e3c8b60bd86be8873e781bef053f466898be16c2..d77d120ddc25173a0f77bdcddcbce86f31292ff9 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/bitops.h>
 #include <linux/bug.h>
 #include <linux/compiler.h>
 #include <linux/delay.h>
@@ -40,6 +41,7 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/time.h>
+#include <linux/vmalloc.h>
 
 #include <asm/byteorder.h>
 #include <asm/page.h>
@@ -80,17 +82,23 @@ struct descriptor {
 #define COMMAND_PTR(regs)      ((regs) + 12)
 #define CONTEXT_MATCH(regs)    ((regs) + 16)
 
-struct ar_buffer {
-       struct descriptor descriptor;
-       struct ar_buffer *next;
-       __le32 data[0];
-};
+#define AR_BUFFER_SIZE (32*1024)
+#define AR_BUFFERS_MIN DIV_ROUND_UP(AR_BUFFER_SIZE, PAGE_SIZE)
+/* we need at least two pages for proper list management */
+#define AR_BUFFERS     (AR_BUFFERS_MIN >= 2 ? AR_BUFFERS_MIN : 2)
+
+#define MAX_ASYNC_PAYLOAD      4096
+#define MAX_AR_PACKET_SIZE     (16 + MAX_ASYNC_PAYLOAD + 4)
+#define AR_WRAPAROUND_PAGES    DIV_ROUND_UP(MAX_AR_PACKET_SIZE, PAGE_SIZE)
 
 struct ar_context {
        struct fw_ohci *ohci;
-       struct ar_buffer *current_buffer;
-       struct ar_buffer *last_buffer;
+       struct page *pages[AR_BUFFERS];
+       void *buffer;
+       struct descriptor *descriptors;
+       dma_addr_t descriptors_bus;
        void *pointer;
+       unsigned int last_buffer_index;
        u32 regs;
        struct tasklet_struct tasklet;
 };
@@ -117,6 +125,8 @@ struct context {
        struct fw_ohci *ohci;
        u32 regs;
        int total_allocation;
+       bool running;
+       bool flushing;
 
        /*
         * List of page-sized buffers for storing DMA descriptors.
@@ -161,6 +171,9 @@ struct iso_context {
        int excess_bytes;
        void *header;
        size_t header_length;
+
+       u8 sync;
+       u8 tags;
 };
 
 #define CONFIG_ROM_SIZE 1024
@@ -177,7 +190,8 @@ struct fw_ohci {
        u32 bus_time;
        bool is_root;
        bool csr_state_setclear_abdicate;
-
+       int n_ir;
+       int n_it;
        /*
         * Spinlock for accessing fw_ohci data.  Never call out of
         * this driver with this lock held.
@@ -186,6 +200,9 @@ struct fw_ohci {
 
        struct mutex phy_reg_mutex;
 
+       void *misc_buffer;
+       dma_addr_t misc_buffer_bus;
+
        struct ar_context ar_request_ctx;
        struct ar_context ar_response_ctx;
        struct context at_request_ctx;
@@ -411,10 +428,6 @@ static const char *tcodes[] = {
        [0xc] = "-reserved-",           [0xd] = "-reserved-",
        [0xe] = "link internal",        [0xf] = "-reserved-",
 };
-static const char *phys[] = {
-       [0x0] = "phy config packet",    [0x1] = "link-on packet",
-       [0x2] = "self-id packet",       [0x3] = "-reserved-",
-};
 
 static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
 {
@@ -433,12 +446,6 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
                return;
        }
 
-       if (header[0] == ~header[1]) {
-               fw_notify("A%c %s, %s, %08x\n",
-                   dir, evts[evt], phys[header[0] >> 30 & 0x3], header[0]);
-               return;
-       }
-
        switch (tcode) {
        case 0x0: case 0x6: case 0x8:
                snprintf(specific, sizeof(specific), " = %08x",
@@ -453,9 +460,13 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
        }
 
        switch (tcode) {
-       case 0xe: case 0xa:
+       case 0xa:
                fw_notify("A%c %s, %s\n", dir, evts[evt], tcodes[tcode]);
                break;
+       case 0xe:
+               fw_notify("A%c %s, PHY %08x %08x\n",
+                         dir, evts[evt], header[1], header[2]);
+               break;
        case 0x0: case 0x1: case 0x4: case 0x5: case 0x9:
                fw_notify("A%c spd %x tl %02x, "
                    "%04x -> %04x, %s, "
@@ -594,59 +605,150 @@ static int ohci_update_phy_reg(struct fw_card *card, int addr,
        return ret;
 }
 
-static void ar_context_link_page(struct ar_context *ctx,
-                                struct ar_buffer *ab, dma_addr_t ab_bus)
+static inline dma_addr_t ar_buffer_bus(struct ar_context *ctx, unsigned int i)
 {
-       size_t offset;
+       return page_private(ctx->pages[i]);
+}
 
-       ab->next = NULL;
-       memset(&ab->descriptor, 0, sizeof(ab->descriptor));
-       ab->descriptor.control        = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
-                                                   DESCRIPTOR_STATUS |
-                                                   DESCRIPTOR_BRANCH_ALWAYS);
-       offset = offsetof(struct ar_buffer, data);
-       ab->descriptor.req_count      = cpu_to_le16(PAGE_SIZE - offset);
-       ab->descriptor.data_address   = cpu_to_le32(ab_bus + offset);
-       ab->descriptor.res_count      = cpu_to_le16(PAGE_SIZE - offset);
-       ab->descriptor.branch_address = 0;
+static void ar_context_link_page(struct ar_context *ctx, unsigned int index)
+{
+       struct descriptor *d;
+
+       d = &ctx->descriptors[index];
+       d->branch_address  &= cpu_to_le32(~0xf);
+       d->res_count       =  cpu_to_le16(PAGE_SIZE);
+       d->transfer_status =  0;
 
        wmb(); /* finish init of new descriptors before branch_address update */
-       ctx->last_buffer->descriptor.branch_address = cpu_to_le32(ab_bus | 1);
-       ctx->last_buffer->next = ab;
-       ctx->last_buffer = ab;
+       d = &ctx->descriptors[ctx->last_buffer_index];
+       d->branch_address  |= cpu_to_le32(1);
+
+       ctx->last_buffer_index = index;
 
        reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
        flush_writes(ctx->ohci);
 }
 
-static int ar_context_add_page(struct ar_context *ctx)
+static void ar_context_release(struct ar_context *ctx)
 {
-       struct device *dev = ctx->ohci->card.device;
-       struct ar_buffer *ab;
-       dma_addr_t uninitialized_var(ab_bus);
+       unsigned int i;
 
-       ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
-       if (ab == NULL)
-               return -ENOMEM;
+       if (ctx->buffer)
+               vm_unmap_ram(ctx->buffer, AR_BUFFERS + AR_WRAPAROUND_PAGES);
 
-       ar_context_link_page(ctx, ab, ab_bus);
+       for (i = 0; i < AR_BUFFERS; i++)
+               if (ctx->pages[i]) {
+                       dma_unmap_page(ctx->ohci->card.device,
+                                      ar_buffer_bus(ctx, i),
+                                      PAGE_SIZE, DMA_FROM_DEVICE);
+                       __free_page(ctx->pages[i]);
+               }
+}
 
-       return 0;
+static void ar_context_abort(struct ar_context *ctx, const char *error_msg)
+{
+       if (reg_read(ctx->ohci, CONTROL_CLEAR(ctx->regs)) & CONTEXT_RUN) {
+               reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
+               flush_writes(ctx->ohci);
+
+               fw_error("AR error: %s; DMA stopped\n", error_msg);
+       }
+       /* FIXME: restart? */
 }
 
-static void ar_context_release(struct ar_context *ctx)
+static inline unsigned int ar_next_buffer_index(unsigned int index)
+{
+       return (index + 1) % AR_BUFFERS;
+}
+
+static inline unsigned int ar_prev_buffer_index(unsigned int index)
+{
+       return (index - 1 + AR_BUFFERS) % AR_BUFFERS;
+}
+
+static inline unsigned int ar_first_buffer_index(struct ar_context *ctx)
+{
+       return ar_next_buffer_index(ctx->last_buffer_index);
+}
+
+/*
+ * We search for the buffer that contains the last AR packet DMA data written
+ * by the controller.
+ */
+static unsigned int ar_search_last_active_buffer(struct ar_context *ctx,
+                                                unsigned int *buffer_offset)
 {
-       struct ar_buffer *ab, *ab_next;
-       size_t offset;
-       dma_addr_t ab_bus;
+       unsigned int i, next_i, last = ctx->last_buffer_index;
+       __le16 res_count, next_res_count;
+
+       i = ar_first_buffer_index(ctx);
+       res_count = ACCESS_ONCE(ctx->descriptors[i].res_count);
+
+       /* A buffer that is not yet completely filled must be the last one. */
+       while (i != last && res_count == 0) {
+
+               /* Peek at the next descriptor. */
+               next_i = ar_next_buffer_index(i);
+               rmb(); /* read descriptors in order */
+               next_res_count = ACCESS_ONCE(
+                               ctx->descriptors[next_i].res_count);
+               /*
+                * If the next descriptor is still empty, we must stop at this
+                * descriptor.
+                */
+               if (next_res_count == cpu_to_le16(PAGE_SIZE)) {
+                       /*
+                        * The exception is when the DMA data for one packet is
+                        * split over three buffers; in this case, the middle
+                        * buffer's descriptor might be never updated by the
+                        * controller and look still empty, and we have to peek
+                        * at the third one.
+                        */
+                       if (MAX_AR_PACKET_SIZE > PAGE_SIZE && i != last) {
+                               next_i = ar_next_buffer_index(next_i);
+                               rmb();
+                               next_res_count = ACCESS_ONCE(
+                                       ctx->descriptors[next_i].res_count);
+                               if (next_res_count != cpu_to_le16(PAGE_SIZE))
+                                       goto next_buffer_is_active;
+                       }
 
-       for (ab = ctx->current_buffer; ab; ab = ab_next) {
-               ab_next = ab->next;
-               offset = offsetof(struct ar_buffer, data);
-               ab_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
-               dma_free_coherent(ctx->ohci->card.device, PAGE_SIZE,
-                                 ab, ab_bus);
+                       break;
+               }
+
+next_buffer_is_active:
+               i = next_i;
+               res_count = next_res_count;
+       }
+
+       rmb(); /* read res_count before the DMA data */
+
+       *buffer_offset = PAGE_SIZE - le16_to_cpu(res_count);
+       if (*buffer_offset > PAGE_SIZE) {
+               *buffer_offset = 0;
+               ar_context_abort(ctx, "corrupted descriptor");
+       }
+
+       return i;
+}
+
+static void ar_sync_buffers_for_cpu(struct ar_context *ctx,
+                                   unsigned int end_buffer_index,
+                                   unsigned int end_buffer_offset)
+{
+       unsigned int i;
+
+       i = ar_first_buffer_index(ctx);
+       while (i != end_buffer_index) {
+               dma_sync_single_for_cpu(ctx->ohci->card.device,
+                                       ar_buffer_bus(ctx, i),
+                                       PAGE_SIZE, DMA_FROM_DEVICE);
+               i = ar_next_buffer_index(i);
        }
+       if (end_buffer_offset > 0)
+               dma_sync_single_for_cpu(ctx->ohci->card.device,
+                                       ar_buffer_bus(ctx, i),
+                                       end_buffer_offset, DMA_FROM_DEVICE);
 }
 
 #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
@@ -689,6 +791,10 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
                p.header[3] = cond_le32_to_cpu(buffer[3]);
                p.header_length = 16;
                p.payload_length = p.header[3] >> 16;
+               if (p.payload_length > MAX_ASYNC_PAYLOAD) {
+                       ar_context_abort(ctx, "invalid packet length");
+                       return NULL;
+               }
                break;
 
        case TCODE_WRITE_RESPONSE:
@@ -699,9 +805,8 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
                break;
 
        default:
-               /* FIXME: Stop context, discard everything, and restart? */
-               p.header_length = 0;
-               p.payload_length = 0;
+               ar_context_abort(ctx, "invalid tcode");
+               return NULL;
        }
 
        p.payload = (void *) buffer + p.header_length;
@@ -751,121 +856,147 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
        return buffer + length + 1;
 }
 
+static void *handle_ar_packets(struct ar_context *ctx, void *p, void *end)
+{
+       void *next;
+
+       while (p < end) {
+               next = handle_ar_packet(ctx, p);
+               if (!next)
+                       return p;
+               p = next;
+       }
+
+       return p;
+}
+
+static void ar_recycle_buffers(struct ar_context *ctx, unsigned int end_buffer)
+{
+       unsigned int i;
+
+       i = ar_first_buffer_index(ctx);
+       while (i != end_buffer) {
+               dma_sync_single_for_device(ctx->ohci->card.device,
+                                          ar_buffer_bus(ctx, i),
+                                          PAGE_SIZE, DMA_FROM_DEVICE);
+               ar_context_link_page(ctx, i);
+               i = ar_next_buffer_index(i);
+       }
+}
+
 static void ar_context_tasklet(unsigned long data)
 {
        struct ar_context *ctx = (struct ar_context *)data;
-       struct ar_buffer *ab;
-       struct descriptor *d;
-       void *buffer, *end;
-       __le16 res_count;
+       unsigned int end_buffer_index, end_buffer_offset;
+       void *p, *end;
 
-       ab = ctx->current_buffer;
-       d = &ab->descriptor;
+       p = ctx->pointer;
+       if (!p)
+               return;
 
-       res_count = ACCESS_ONCE(d->res_count);
-       if (res_count == 0) {
-               size_t size, size2, rest, pktsize, size3, offset;
-               dma_addr_t start_bus;
-               void *start;
+       end_buffer_index = ar_search_last_active_buffer(ctx,
+                                                       &end_buffer_offset);
+       ar_sync_buffers_for_cpu(ctx, end_buffer_index, end_buffer_offset);
+       end = ctx->buffer + end_buffer_index * PAGE_SIZE + end_buffer_offset;
 
+       if (end_buffer_index < ar_first_buffer_index(ctx)) {
                /*
-                * This descriptor is finished and we may have a
-                * packet split across this and the next buffer. We
-                * reuse the page for reassembling the split packet.
+                * The filled part of the overall buffer wraps around; handle
+                * all packets up to the buffer end here.  If the last packet
+                * wraps around, its tail will be visible after the buffer end
+                * because the buffer start pages are mapped there again.
                 */
+               void *buffer_end = ctx->buffer + AR_BUFFERS * PAGE_SIZE;
+               p = handle_ar_packets(ctx, p, buffer_end);
+               if (p < buffer_end)
+                       goto error;
+               /* adjust p to point back into the actual buffer */
+               p -= AR_BUFFERS * PAGE_SIZE;
+       }
 
-               offset = offsetof(struct ar_buffer, data);
-               start = ab;
-               start_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
-               buffer = ab->data;
-
-               ab = ab->next;
-               d = &ab->descriptor;
-               size = start + PAGE_SIZE - ctx->pointer;
-               /* valid buffer data in the next page */
-               rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count);
-               /* what actually fits in this page */
-               size2 = min(rest, (size_t)PAGE_SIZE - offset - size);
-               memmove(buffer, ctx->pointer, size);
-               memcpy(buffer + size, ab->data, size2);
-
-               while (size > 0) {
-                       void *next = handle_ar_packet(ctx, buffer);
-                       pktsize = next - buffer;
-                       if (pktsize >= size) {
-                               /*
-                                * We have handled all the data that was
-                                * originally in this page, so we can now
-                                * continue in the next page.
-                                */
-                               buffer = next;
-                               break;
-                       }
-                       /* move the next packet to the start of the buffer */
-                       memmove(buffer, next, size + size2 - pktsize);
-                       size -= pktsize;
-                       /* fill up this page again */
-                       size3 = min(rest - size2,
-                                   (size_t)PAGE_SIZE - offset - size - size2);
-                       memcpy(buffer + size + size2,
-                              (void *) ab->data + size2, size3);
-                       size2 += size3;
-               }
-
-               if (rest > 0) {
-                       /* handle the packets that are fully in the next page */
-                       buffer = (void *) ab->data +
-                                       (buffer - (start + offset + size));
-                       end = (void *) ab->data + rest;
-
-                       while (buffer < end)
-                               buffer = handle_ar_packet(ctx, buffer);
+       p = handle_ar_packets(ctx, p, end);
+       if (p != end) {
+               if (p > end)
+                       ar_context_abort(ctx, "inconsistent descriptor");
+               goto error;
+       }
 
-                       ctx->current_buffer = ab;
-                       ctx->pointer = end;
+       ctx->pointer = p;
+       ar_recycle_buffers(ctx, end_buffer_index);
 
-                       ar_context_link_page(ctx, start, start_bus);
-               } else {
-                       ctx->pointer = start + PAGE_SIZE;
-               }
-       } else {
-               buffer = ctx->pointer;
-               ctx->pointer = end =
-                       (void *) ab + PAGE_SIZE - le16_to_cpu(res_count);
+       return;
 
-               while (buffer < end)
-                       buffer = handle_ar_packet(ctx, buffer);
-       }
+error:
+       ctx->pointer = NULL;
 }
 
-static int ar_context_init(struct ar_context *ctx,
-                          struct fw_ohci *ohci, u32 regs)
+static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci,
+                          unsigned int descriptors_offset, u32 regs)
 {
-       struct ar_buffer ab;
+       unsigned int i;
+       dma_addr_t dma_addr;
+       struct page *pages[AR_BUFFERS + AR_WRAPAROUND_PAGES];
+       struct descriptor *d;
 
        ctx->regs        = regs;
        ctx->ohci        = ohci;
-       ctx->last_buffer = &ab;
        tasklet_init(&ctx->tasklet, ar_context_tasklet, (unsigned long)ctx);
 
-       ar_context_add_page(ctx);
-       ar_context_add_page(ctx);
-       ctx->current_buffer = ab.next;
-       ctx->pointer = ctx->current_buffer->data;
+       for (i = 0; i < AR_BUFFERS; i++) {
+               ctx->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32);
+               if (!ctx->pages[i])
+                       goto out_of_memory;
+               dma_addr = dma_map_page(ohci->card.device, ctx->pages[i],
+                                       0, PAGE_SIZE, DMA_FROM_DEVICE);
+               if (dma_mapping_error(ohci->card.device, dma_addr)) {
+                       __free_page(ctx->pages[i]);
+                       ctx->pages[i] = NULL;
+                       goto out_of_memory;
+               }
+               set_page_private(ctx->pages[i], dma_addr);
+       }
+
+       for (i = 0; i < AR_BUFFERS; i++)
+               pages[i]              = ctx->pages[i];
+       for (i = 0; i < AR_WRAPAROUND_PAGES; i++)
+               pages[AR_BUFFERS + i] = ctx->pages[i];
+       ctx->buffer = vm_map_ram(pages, AR_BUFFERS + AR_WRAPAROUND_PAGES,
+                                -1, PAGE_KERNEL_RO);
+       if (!ctx->buffer)
+               goto out_of_memory;
+
+       ctx->descriptors     = ohci->misc_buffer     + descriptors_offset;
+       ctx->descriptors_bus = ohci->misc_buffer_bus + descriptors_offset;
+
+       for (i = 0; i < AR_BUFFERS; i++) {
+               d = &ctx->descriptors[i];
+               d->req_count      = cpu_to_le16(PAGE_SIZE);
+               d->control        = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
+                                               DESCRIPTOR_STATUS |
+                                               DESCRIPTOR_BRANCH_ALWAYS);
+               d->data_address   = cpu_to_le32(ar_buffer_bus(ctx, i));
+               d->branch_address = cpu_to_le32(ctx->descriptors_bus +
+                       ar_next_buffer_index(i) * sizeof(struct descriptor));
+       }
 
        return 0;
+
+out_of_memory:
+       ar_context_release(ctx);
+
+       return -ENOMEM;
 }
 
 static void ar_context_run(struct ar_context *ctx)
 {
-       struct ar_buffer *ab = ctx->current_buffer;
-       dma_addr_t ab_bus;
-       size_t offset;
+       unsigned int i;
+
+       for (i = 0; i < AR_BUFFERS; i++)
+               ar_context_link_page(ctx, i);
 
-       offset = offsetof(struct ar_buffer, data);
-       ab_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
+       ctx->pointer = ctx->buffer;
 
-       reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ab_bus | 1);
+       reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ctx->descriptors_bus | 1);
        reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN);
        flush_writes(ctx->ohci);
 }
@@ -1042,6 +1173,7 @@ static void context_run(struct context *ctx, u32 extra)
                  le32_to_cpu(ctx->last->branch_address));
        reg_write(ohci, CONTROL_CLEAR(ctx->regs), ~0);
        reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN | extra);
+       ctx->running = true;
        flush_writes(ohci);
 }
 
@@ -1069,6 +1201,7 @@ static void context_stop(struct context *ctx)
        int i;
 
        reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
+       ctx->running = false;
        flush_writes(ctx->ohci);
 
        for (i = 0; i < 10; i++) {
@@ -1099,7 +1232,6 @@ static int at_context_queue_packet(struct context *ctx,
        struct descriptor *d, *last;
        __le32 *header;
        int z, tcode;
-       u32 reg;
 
        d = context_get_descriptors(ctx, 4, &d_bus);
        if (d == NULL) {
@@ -1113,21 +1245,27 @@ static int at_context_queue_packet(struct context *ctx,
        /*
         * The DMA format for asyncronous link packets is different
         * from the IEEE1394 layout, so shift the fields around
-        * accordingly.  If header_length is 8, it's a PHY packet, to
-        * which we need to prepend an extra quadlet.
+        * accordingly.
         */
 
+       tcode = (packet->header[0] >> 4) & 0x0f;
        header = (__le32 *) &d[1];
-       switch (packet->header_length) {
-       case 16:
-       case 12:
+       switch (tcode) {
+       case TCODE_WRITE_QUADLET_REQUEST:
+       case TCODE_WRITE_BLOCK_REQUEST:
+       case TCODE_WRITE_RESPONSE:
+       case TCODE_READ_QUADLET_REQUEST:
+       case TCODE_READ_BLOCK_REQUEST:
+       case TCODE_READ_QUADLET_RESPONSE:
+       case TCODE_READ_BLOCK_RESPONSE:
+       case TCODE_LOCK_REQUEST:
+       case TCODE_LOCK_RESPONSE:
                header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
                                        (packet->speed << 16));
                header[1] = cpu_to_le32((packet->header[1] & 0xffff) |
                                        (packet->header[0] & 0xffff0000));
                header[2] = cpu_to_le32(packet->header[2]);
 
-               tcode = (packet->header[0] >> 4) & 0x0f;
                if (TCODE_IS_BLOCK_PACKET(tcode))
                        header[3] = cpu_to_le32(packet->header[3]);
                else
@@ -1136,18 +1274,18 @@ static int at_context_queue_packet(struct context *ctx,
                d[0].req_count = cpu_to_le16(packet->header_length);
                break;
 
-       case 8:
+       case TCODE_LINK_INTERNAL:
                header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) |
                                        (packet->speed << 16));
-               header[1] = cpu_to_le32(packet->header[0]);
-               header[2] = cpu_to_le32(packet->header[1]);
+               header[1] = cpu_to_le32(packet->header[1]);
+               header[2] = cpu_to_le32(packet->header[2]);
                d[0].req_count = cpu_to_le16(12);
 
-               if (is_ping_packet(packet->header))
+               if (is_ping_packet(&packet->header[1]))
                        d[0].control |= cpu_to_le16(DESCRIPTOR_PING);
                break;
 
-       case 4:
+       case TCODE_STREAM_DATA:
                header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
                                        (packet->speed << 16));
                header[1] = cpu_to_le32(packet->header[0] & 0xffff0000);
@@ -1197,6 +1335,8 @@ static int at_context_queue_packet(struct context *ctx,
         * some controllers (like a JMicron JMB381 PCI-e) misbehave and wind
         * up stalling out.  So we just bail out in software and try again
         * later, and everyone is happy.
+        * FIXME: Test of IntEvent.busReset may no longer be necessary since we
+        *        flush AT queues in bus_reset_tasklet.
         * FIXME: Document how the locking works.
         */
        if (ohci->generation != packet->generation ||
@@ -1210,14 +1350,23 @@ static int at_context_queue_packet(struct context *ctx,
 
        context_append(ctx, d, z, 4 - z);
 
-       /* If the context isn't already running, start it up. */
-       reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs));
-       if ((reg & CONTEXT_RUN) == 0)
+       if (!ctx->running)
                context_run(ctx, 0);
 
        return 0;
 }
 
+static void at_context_flush(struct context *ctx)
+{
+       tasklet_disable(&ctx->tasklet);
+
+       ctx->flushing = true;
+       context_tasklet((unsigned long)ctx);
+       ctx->flushing = false;
+
+       tasklet_enable(&ctx->tasklet);
+}
+
 static int handle_at_packet(struct context *context,
                            struct descriptor *d,
                            struct descriptor *last)
@@ -1227,7 +1376,7 @@ static int handle_at_packet(struct context *context,
        struct fw_ohci *ohci = context->ohci;
        int evt;
 
-       if (last->transfer_status == 0)
+       if (last->transfer_status == 0 && !context->flushing)
                /* This descriptor isn't done yet, stop iteration. */
                return 0;
 
@@ -1261,11 +1410,15 @@ static int handle_at_packet(struct context *context,
                break;
 
        case OHCI1394_evt_missing_ack:
-               /*
-                * Using a valid (current) generation count, but the
-                * node is not on the bus or not sending acks.
-                */
-               packet->ack = RCODE_NO_ACK;
+               if (context->flushing)
+                       packet->ack = RCODE_GENERATION;
+               else {
+                       /*
+                        * Using a valid (current) generation count, but the
+                        * node is not on the bus or not sending acks.
+                        */
+                       packet->ack = RCODE_NO_ACK;
+               }
                break;
 
        case ACK_COMPLETE + 0x10:
@@ -1278,6 +1431,13 @@ static int handle_at_packet(struct context *context,
                packet->ack = evt - 0x10;
                break;
 
+       case OHCI1394_evt_no_status:
+               if (context->flushing) {
+                       packet->ack = RCODE_GENERATION;
+                       break;
+               }
+               /* fall through */
+
        default:
                packet->ack = RCODE_SEND_ERROR;
                break;
@@ -1583,9 +1743,23 @@ static void bus_reset_tasklet(unsigned long data)
        /* FIXME: Document how the locking works. */
        spin_lock_irqsave(&ohci->lock, flags);
 
-       ohci->generation = generation;
+       ohci->generation = -1; /* prevent AT packet queueing */
        context_stop(&ohci->at_request_ctx);
        context_stop(&ohci->at_response_ctx);
+
+       spin_unlock_irqrestore(&ohci->lock, flags);
+
+       /*
+        * Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent
+        * packets in the AT queues and software needs to drain them.
+        * Some OHCI 1.1 controllers (JMicron) apparently require this too.
+        */
+       at_context_flush(&ohci->at_request_ctx);
+       at_context_flush(&ohci->at_response_ctx);
+
+       spin_lock_irqsave(&ohci->lock, flags);
+
+       ohci->generation = generation;
        reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
 
        if (ohci->quirks & QUIRK_RESET_PACKET)
@@ -1653,8 +1827,12 @@ static irqreturn_t irq_handler(int irq, void *data)
        if (!event || !~event)
                return IRQ_NONE;
 
-       /* busReset must not be cleared yet, see OHCI 1.1 clause 7.2.3.2 */
-       reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
+       /*
+        * busReset and postedWriteErr must not be cleared yet
+        * (OHCI 1.1 clauses 7.2.3.2 and 13.2.8.1)
+        */
+       reg_write(ohci, OHCI1394_IntEventClear,
+                 event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr));
        log_irqs(event);
 
        if (event & OHCI1394_selfIDComplete)
@@ -1672,30 +1850,41 @@ static irqreturn_t irq_handler(int irq, void *data)
        if (event & OHCI1394_respTxComplete)
                tasklet_schedule(&ohci->at_response_ctx.tasklet);
 
-       iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
-       reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event);
+       if (event & OHCI1394_isochRx) {
+               iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
+               reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event);
 
-       while (iso_event) {
-               i = ffs(iso_event) - 1;
-               tasklet_schedule(&ohci->ir_context_list[i].context.tasklet);
-               iso_event &= ~(1 << i);
+               while (iso_event) {
+                       i = ffs(iso_event) - 1;
+                       tasklet_schedule(
+                               &ohci->ir_context_list[i].context.tasklet);
+                       iso_event &= ~(1 << i);
+               }
        }
 
-       iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear);
-       reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event);
+       if (event & OHCI1394_isochTx) {
+               iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear);
+               reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event);
 
-       while (iso_event) {
-               i = ffs(iso_event) - 1;
-               tasklet_schedule(&ohci->it_context_list[i].context.tasklet);
-               iso_event &= ~(1 << i);
+               while (iso_event) {
+                       i = ffs(iso_event) - 1;
+                       tasklet_schedule(
+                               &ohci->it_context_list[i].context.tasklet);
+                       iso_event &= ~(1 << i);
+               }
        }
 
        if (unlikely(event & OHCI1394_regAccessFail))
                fw_error("Register access failure - "
                         "please notify linux1394-devel@lists.sf.net\n");
 
-       if (unlikely(event & OHCI1394_postedWriteErr))
+       if (unlikely(event & OHCI1394_postedWriteErr)) {
+               reg_read(ohci, OHCI1394_PostedWriteAddressHi);
+               reg_read(ohci, OHCI1394_PostedWriteAddressLo);
+               reg_write(ohci, OHCI1394_IntEventClear,
+                         OHCI1394_postedWriteErr);
                fw_error("PCI posted write error\n");
+       }
 
        if (unlikely(event & OHCI1394_cycleTooLong)) {
                if (printk_ratelimit())
@@ -1719,7 +1908,8 @@ static irqreturn_t irq_handler(int irq, void *data)
                spin_lock(&ohci->lock);
                update_bus_time(ohci);
                spin_unlock(&ohci->lock);
-       }
+       } else
+               flush_writes(ohci);
 
        return IRQ_HANDLED;
 }
@@ -2495,6 +2685,10 @@ static int ohci_start_iso(struct fw_iso_context *base,
                reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index);
                reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match);
                context_run(&ctx->context, control);
+
+               ctx->sync = sync;
+               ctx->tags = tags;
+
                break;
        }
 
@@ -2592,6 +2786,26 @@ static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels)
        return ret;
 }
 
+#ifdef CONFIG_PM
+static void ohci_resume_iso_dma(struct fw_ohci *ohci)
+{
+       int i;
+       struct iso_context *ctx;
+
+       for (i = 0 ; i < ohci->n_ir ; i++) {
+               ctx = &ohci->ir_context_list[i];
+               if (ctx->context.running)
+                       ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags);
+       }
+
+       for (i = 0 ; i < ohci->n_it ; i++) {
+               ctx = &ohci->it_context_list[i];
+               if (ctx->context.running)
+                       ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags);
+       }
+}
+#endif
+
 static int queue_iso_transmit(struct iso_context *ctx,
                              struct fw_iso_packet *packet,
                              struct fw_iso_buffer *buffer,
@@ -2901,7 +3115,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
        struct fw_ohci *ohci;
        u32 bus_options, max_receive, link_speed, version;
        u64 guid;
-       int i, err, n_ir, n_it;
+       int i, err;
        size_t size;
 
        ohci = kzalloc(sizeof(*ohci), GFP_KERNEL);
@@ -2955,31 +3169,55 @@ static int __devinit pci_probe(struct pci_dev *dev,
        if (param_quirks)
                ohci->quirks = param_quirks;
 
-       ar_context_init(&ohci->ar_request_ctx, ohci,
-                       OHCI1394_AsReqRcvContextControlSet);
+       /*
+        * Because dma_alloc_coherent() allocates at least one page,
+        * we save space by using a common buffer for the AR request/
+        * response descriptors and the self IDs buffer.
+        */
+       BUILD_BUG_ON(AR_BUFFERS * sizeof(struct descriptor) > PAGE_SIZE/4);
+       BUILD_BUG_ON(SELF_ID_BUF_SIZE > PAGE_SIZE/2);
+       ohci->misc_buffer = dma_alloc_coherent(ohci->card.device,
+                                              PAGE_SIZE,
+                                              &ohci->misc_buffer_bus,
+                                              GFP_KERNEL);
+       if (!ohci->misc_buffer) {
+               err = -ENOMEM;
+               goto fail_iounmap;
+       }
+
+       err = ar_context_init(&ohci->ar_request_ctx, ohci, 0,
+                             OHCI1394_AsReqRcvContextControlSet);
+       if (err < 0)
+               goto fail_misc_buf;
 
-       ar_context_init(&ohci->ar_response_ctx, ohci,
-                       OHCI1394_AsRspRcvContextControlSet);
+       err = ar_context_init(&ohci->ar_response_ctx, ohci, PAGE_SIZE/4,
+                             OHCI1394_AsRspRcvContextControlSet);
+       if (err < 0)
+               goto fail_arreq_ctx;
 
-       context_init(&ohci->at_request_ctx, ohci,
-                    OHCI1394_AsReqTrContextControlSet, handle_at_packet);
+       err = context_init(&ohci->at_request_ctx, ohci,
+                          OHCI1394_AsReqTrContextControlSet, handle_at_packet);
+       if (err < 0)
+               goto fail_arrsp_ctx;
 
-       context_init(&ohci->at_response_ctx, ohci,
-                    OHCI1394_AsRspTrContextControlSet, handle_at_packet);
+       err = context_init(&ohci->at_response_ctx, ohci,
+                          OHCI1394_AsRspTrContextControlSet, handle_at_packet);
+       if (err < 0)
+               goto fail_atreq_ctx;
 
        reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
        ohci->ir_context_channels = ~0ULL;
        ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
        reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0);
-       n_ir = hweight32(ohci->ir_context_mask);
-       size = sizeof(struct iso_context) * n_ir;
+       ohci->n_ir = hweight32(ohci->ir_context_mask);
+       size = sizeof(struct iso_context) * ohci->n_ir;
        ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
 
        reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
        ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
        reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
-       n_it = hweight32(ohci->it_context_mask);
-       size = sizeof(struct iso_context) * n_it;
+       ohci->n_it = hweight32(ohci->it_context_mask);
+       size = sizeof(struct iso_context) * ohci->n_it;
        ohci->it_context_list = kzalloc(size, GFP_KERNEL);
 
        if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) {
@@ -2987,15 +3225,8 @@ static int __devinit pci_probe(struct pci_dev *dev,
                goto fail_contexts;
        }
 
-       /* self-id dma buffer allocation */
-       ohci->self_id_cpu = dma_alloc_coherent(ohci->card.device,
-                                              SELF_ID_BUF_SIZE,
-                                              &ohci->self_id_bus,
-                                              GFP_KERNEL);
-       if (ohci->self_id_cpu == NULL) {
-               err = -ENOMEM;
-               goto fail_contexts;
-       }
+       ohci->self_id_cpu = ohci->misc_buffer     + PAGE_SIZE/2;
+       ohci->self_id_bus = ohci->misc_buffer_bus + PAGE_SIZE/2;
 
        bus_options = reg_read(ohci, OHCI1394_BusOptions);
        max_receive = (bus_options >> 12) & 0xf;
@@ -3005,26 +3236,30 @@ static int __devinit pci_probe(struct pci_dev *dev,
 
        err = fw_card_add(&ohci->card, max_receive, link_speed, guid);
        if (err)
-               goto fail_self_id;
+               goto fail_contexts;
 
        version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
        fw_notify("Added fw-ohci device %s, OHCI v%x.%x, "
                  "%d IR + %d IT contexts, quirks 0x%x\n",
                  dev_name(&dev->dev), version >> 16, version & 0xff,
-                 n_ir, n_it, ohci->quirks);
+                 ohci->n_ir, ohci->n_it, ohci->quirks);
 
        return 0;
 
- fail_self_id:
-       dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE,
-                         ohci->self_id_cpu, ohci->self_id_bus);
  fail_contexts:
        kfree(ohci->ir_context_list);
        kfree(ohci->it_context_list);
        context_release(&ohci->at_response_ctx);
+ fail_atreq_ctx:
        context_release(&ohci->at_request_ctx);
+ fail_arrsp_ctx:
        ar_context_release(&ohci->ar_response_ctx);
+ fail_arreq_ctx:
        ar_context_release(&ohci->ar_request_ctx);
+ fail_misc_buf:
+       dma_free_coherent(ohci->card.device, PAGE_SIZE,
+                         ohci->misc_buffer, ohci->misc_buffer_bus);
+ fail_iounmap:
        pci_iounmap(dev, ohci->registers);
  fail_iomem:
        pci_release_region(dev, 0);
@@ -3063,10 +3298,10 @@ static void pci_remove(struct pci_dev *dev)
        if (ohci->config_rom)
                dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
                                  ohci->config_rom, ohci->config_rom_bus);
-       dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE,
-                         ohci->self_id_cpu, ohci->self_id_bus);
        ar_context_release(&ohci->ar_request_ctx);
        ar_context_release(&ohci->ar_response_ctx);
+       dma_free_coherent(ohci->card.device, PAGE_SIZE,
+                         ohci->misc_buffer, ohci->misc_buffer_bus);
        context_release(&ohci->at_request_ctx);
        context_release(&ohci->at_response_ctx);
        kfree(ohci->it_context_list);
@@ -3117,7 +3352,20 @@ static int pci_resume(struct pci_dev *dev)
                return err;
        }
 
-       return ohci_enable(&ohci->card, NULL, 0);
+       /* Some systems don't setup GUID register on resume from ram  */
+       if (!reg_read(ohci, OHCI1394_GUIDLo) &&
+                                       !reg_read(ohci, OHCI1394_GUIDHi)) {
+               reg_write(ohci, OHCI1394_GUIDLo, (u32)ohci->card.guid);
+               reg_write(ohci, OHCI1394_GUIDHi, (u32)(ohci->card.guid >> 32));
+       }
+
+       err = ohci_enable(&ohci->card, NULL, 0);
+       if (err)
+               return err;
+
+       ohci_resume_iso_dma(ohci);
+
+       return 0;
 }
 #endif
 
index 148a322d8f5d7c45d0487351635f89eb9a9a0949..934a96a78540c57a525d722f25480012be3449f8 100644 (file)
@@ -1472,8 +1472,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
        list_del(&bdev->device_list);
        mutex_unlock(&glob->device_list_mutex);
 
-       if (!cancel_delayed_work(&bdev->wq))
-               flush_scheduled_work();
+       cancel_delayed_work_sync(&bdev->wq);
 
        while (ttm_bo_delayed_delete(bdev, true))
                ;
index 41d9a5b73c03ebae477655eeff56d24e4766d1a0..fe096a7cc0d77d940977dce1fc2196e5764873b7 100644 (file)
@@ -659,7 +659,7 @@ int vmw_fb_off(struct vmw_private *vmw_priv)
        par->dirty.active = false;
        spin_unlock_irqrestore(&par->dirty.lock, flags);
 
-       flush_scheduled_work();
+       flush_delayed_work_sync(&info->deferred_work);
 
        par->bo_ptr = NULL;
        ttm_bo_kunmap(&par->map);
index 401acecc7f32b2d1288cd29e408f0ba01a4aa5a4..ffbc278647bfc21cc13f247c60fa912d9c631b1f 100644 (file)
@@ -150,6 +150,16 @@ config DRAGONRISE_FF
        Say Y here if you want to enable force feedback support for DragonRise Inc.
        game controllers.
 
+config HID_EMS_FF
+       tristate "EMS Production Inc. force feedback support"
+       depends on USB_HID
+       select INPUT_FF_MEMLESS
+       ---help---
+       Say Y here if you want to enable force feedback support for devices by
+       EMS Production Ltd.
+       Currently the following devices are known to be supported:
+        - Trio Linker Plus II
+
 config HID_EGALAX
        tristate "eGalax multi-touch panel"
        depends on USB_HID
@@ -397,6 +407,13 @@ config HID_ROCCAT_KONE
        ---help---
        Support for Roccat Kone mouse.
 
+config HID_ROCCAT_KONEPLUS
+       tristate "Roccat Kone[+] mouse support"
+       depends on USB_HID
+       select HID_ROCCAT
+       ---help---
+       Support for Roccat Kone[+] mouse.
+
 config HID_ROCCAT_PYRA
        tristate "Roccat Pyra mouse support"
        depends on USB_HID
index c335605b920038098886b927cdf3340effbd0fd0..6eae9a90b8dd96f1769918453f219ac18367d2ea 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Makefile for the HID driver
 #
-hid-objs                       := hid-core.o hid-input.o
+hid-y                  := hid-core.o hid-input.o
 
 ifdef CONFIG_DEBUG_FS
        hid-objs                += hid-debug.o
@@ -11,18 +11,18 @@ obj-$(CONFIG_HID)           += hid.o
 
 hid-$(CONFIG_HIDRAW)           += hidraw.o
 
-hid-logitech-objs              := hid-lg.o
+hid-logitech-y         := hid-lg.o
 ifdef CONFIG_LOGITECH_FF
-       hid-logitech-objs       += hid-lgff.o
+       hid-logitech-y  += hid-lgff.o
 endif
 ifdef CONFIG_LOGIRUMBLEPAD2_FF
-       hid-logitech-objs       += hid-lg2ff.o
+       hid-logitech-y  += hid-lg2ff.o
 endif
 ifdef CONFIG_LOGIG940_FF
-       hid-logitech-objs       += hid-lg3ff.o
+       hid-logitech-y  += hid-lg3ff.o
 endif
 ifdef CONFIG_LOGIWII_FF
-       hid-logitech-objs       += hid-lg4ff.o
+       hid-logitech-y  += hid-lg4ff.o
 endif
 
 obj-$(CONFIG_HID_3M_PCT)       += hid-3m-pct.o
@@ -35,6 +35,7 @@ obj-$(CONFIG_HID_CHERRY)      += hid-cherry.o
 obj-$(CONFIG_HID_CHICONY)      += hid-chicony.o
 obj-$(CONFIG_HID_CYPRESS)      += hid-cypress.o
 obj-$(CONFIG_HID_DRAGONRISE)   += hid-drff.o
+obj-$(CONFIG_HID_EMS_FF)       += hid-emsff.o
 obj-$(CONFIG_HID_EGALAX)       += hid-egalax.o
 obj-$(CONFIG_HID_ELECOM)       += hid-elecom.o
 obj-$(CONFIG_HID_EZKEY)                += hid-ezkey.o
@@ -55,6 +56,7 @@ obj-$(CONFIG_HID_PETALYNX)    += hid-petalynx.o
 obj-$(CONFIG_HID_PICOLCD)      += hid-picolcd.o
 obj-$(CONFIG_HID_ROCCAT)       += hid-roccat.o
 obj-$(CONFIG_HID_ROCCAT_KONE)  += hid-roccat-kone.o
+obj-$(CONFIG_HID_ROCCAT_KONEPLUS)      += hid-roccat-koneplus.o
 obj-$(CONFIG_HID_ROCCAT_PYRA)  += hid-roccat-pyra.o
 obj-$(CONFIG_HID_SAMSUNG)      += hid-samsung.o
 obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
index 4fb7c7528d1666d31057d859e93f2689879d1e9a..5243ae2d37300eeec72447b3754d95c944ab0c1f 100644 (file)
@@ -246,7 +246,7 @@ static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
        if (!md) {
-               dev_err(&hdev->dev, "cannot allocate 3M data\n");
+               hid_err(hdev, "cannot allocate 3M data\n");
                return -ENOMEM;
        }
        hid_set_drvdata(hdev, md);
index 1666c1684e79d922858ff8c6c4e6f530e50446f5..902d1dfeb1b52f82e8cfb4998e56086cf65fbe53 100644 (file)
@@ -93,7 +93,7 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        a4 = kzalloc(sizeof(*a4), GFP_KERNEL);
        if (a4 == NULL) {
-               dev_err(&hdev->dev, "can't alloc device descriptor\n");
+               hid_err(hdev, "can't alloc device descriptor\n");
                ret = -ENOMEM;
                goto err_free;
        }
@@ -104,13 +104,13 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
index eaeca564a8d3e6643f1222f9be032740a158ee0a..61aa712333927815e5cb9d0d4777e8de3dacd1af 100644 (file)
@@ -16,6 +16,8 @@
  * any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
@@ -59,6 +61,27 @@ struct apple_key_translation {
        u8 flags;
 };
 
+static const struct apple_key_translation macbookair_fn_keys[] = {
+       { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_ENTER,    KEY_INSERT },
+       { KEY_F1,       KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+       { KEY_F2,       KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
+       { KEY_F3,       KEY_SCALE,          APPLE_FLAG_FKEY },
+       { KEY_F4,       KEY_DASHBOARD,      APPLE_FLAG_FKEY },
+       { KEY_F6,       KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
+       { KEY_F7,       KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
+       { KEY_F8,       KEY_NEXTSONG,       APPLE_FLAG_FKEY },
+       { KEY_F9,       KEY_MUTE,           APPLE_FLAG_FKEY },
+       { KEY_F10,      KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
+       { KEY_F11,      KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
+       { KEY_F12,      KEY_EJECTCD,        APPLE_FLAG_FKEY },
+       { KEY_UP,       KEY_PAGEUP },
+       { KEY_DOWN,     KEY_PAGEDOWN },
+       { KEY_LEFT,     KEY_HOME },
+       { KEY_RIGHT,    KEY_END },
+       { }
+};
+
 static const struct apple_key_translation apple_fn_keys[] = {
        { KEY_BACKSPACE, KEY_DELETE },
        { KEY_ENTER,    KEY_INSERT },
@@ -146,7 +169,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
                struct hid_usage *usage, __s32 value)
 {
        struct apple_sc *asc = hid_get_drvdata(hid);
-       const struct apple_key_translation *trans;
+       const struct apple_key_translation *trans, *table;
 
        if (usage->code == KEY_FN) {
                asc->fn_on = !!value;
@@ -157,10 +180,16 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
        if (fnmode) {
                int do_translate;
 
-               trans = apple_find_translation((hid->product < 0x21d ||
-                                       hid->product >= 0x300) ?
-                                       powerbook_fn_keys : apple_fn_keys,
-                                       usage->code);
+               if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
+                               hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
+                       table = macbookair_fn_keys;
+               else if (hid->product < 0x21d || hid->product >= 0x300)
+                       table = powerbook_fn_keys;
+               else
+                       table = apple_fn_keys;
+
+               trans = apple_find_translation (table, usage->code);
+
                if (trans) {
                        if (test_bit(usage->code, asc->pressed_fn))
                                do_translate = 1;
@@ -253,8 +282,8 @@ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 
        if ((asc->quirks & APPLE_RDESC_JIS) && *rsize >= 60 &&
                        rdesc[53] == 0x65 && rdesc[59] == 0x65) {
-               dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report "
-                               "descriptor\n");
+               hid_info(hdev,
+                        "fixing up MacBook JIS keyboard report descriptor\n");
                rdesc[53] = rdesc[59] = 0xe7;
        }
        return rdesc;
@@ -324,7 +353,7 @@ static int apple_probe(struct hid_device *hdev,
 
        asc = kzalloc(sizeof(*asc), GFP_KERNEL);
        if (asc == NULL) {
-               dev_err(&hdev->dev, "can't alloc apple descriptor\n");
+               hid_err(hdev, "can't alloc apple descriptor\n");
                return -ENOMEM;
        }
 
@@ -334,7 +363,7 @@ static int apple_probe(struct hid_device *hdev,
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
@@ -345,7 +374,7 @@ static int apple_probe(struct hid_device *hdev,
 
        ret = hid_hw_start(hdev, connect_mask);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
@@ -440,6 +469,18 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
@@ -473,7 +514,7 @@ static int __init apple_init(void)
 
        ret = hid_register_driver(&apple_driver);
        if (ret)
-               printk(KERN_ERR "can't register apple driver\n");
+               pr_err("can't register apple driver\n");
 
        return ret;
 }
index f42ee140738a219a7cb8e1ef1d8565aca214f718..e5b961d6ff22084f74bd2f648572f4aab41a0759 100644 (file)
@@ -73,14 +73,14 @@ static int axff_init(struct hid_device *hid)
        int error;
 
        if (list_empty(report_list)) {
-               dev_err(&hid->dev, "no output reports found\n");
+               hid_err(hid, "no output reports found\n");
                return -ENODEV;
        }
 
        report = list_first_entry(report_list, struct hid_report, list);
 
        if (report->maxfield < 4) {
-               dev_err(&hid->dev, "no fields in the report: %d\n", report->maxfield);
+               hid_err(hid, "no fields in the report: %d\n", report->maxfield);
                return -ENODEV;
        }
 
@@ -101,7 +101,7 @@ static int axff_init(struct hid_device *hid)
        axff->report->field[3]->value[0] = 0x00;
        usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
 
-       dev_info(&hid->dev, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n");
+       hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n");
 
        return 0;
 
@@ -114,17 +114,17 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int error;
 
-       dev_dbg(&hdev->dev, "ACRUX HID hardware probe...");
+       dev_dbg(&hdev->dev, "ACRUX HID hardware probe...\n");
 
        error = hid_parse(hdev);
        if (error) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                return error;
        }
 
        error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
        if (error) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                return error;
        }
 
@@ -134,7 +134,7 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
                 * Do not fail device initialization completely as device
                 * may still be partially operable, just warn.
                 */
-               dev_warn(&hdev->dev,
+               hid_warn(hdev,
                         "Failed to enable force feedback support, error: %d\n",
                         error);
        }
index 4ce7aa3a519f9ccc52d7b1cdcfe3df8f8d16bce1..a1a765a5b08a96057cbcbbac26835045cbd51dd1 100644 (file)
@@ -56,14 +56,14 @@ static int belkin_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
                ((quirks & BELKIN_HIDDEV) ? HID_CONNECT_HIDDEV_FORCE : 0));
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
index 5925bdcd417dbbf74d878b52fedcbc24a4d4de31..375b50929a507ad30144a604402ae1ec4df19033 100644 (file)
@@ -207,7 +207,7 @@ static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        td = kmalloc(sizeof(struct cando_data), GFP_KERNEL);
        if (!td) {
-               dev_err(&hdev->dev, "cannot allocate Cando Touch data\n");
+               hid_err(hdev, "cannot allocate Cando Touch data\n");
                return -ENOMEM;
        }
        hid_set_drvdata(hdev, td);
index e880086c2311224d7d7ea9fc1ba7d0592bbaf29d..888ece68a47cb0bfb402a481ac1f97adfc3ee4c9 100644 (file)
@@ -30,8 +30,7 @@ static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
        if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
-               dev_info(&hdev->dev, "fixing up Cherry Cymotion report "
-                               "descriptor\n");
+               hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n");
                rdesc[11] = rdesc[16] = 0xff;
                rdesc[12] = rdesc[17] = 0x03;
        }
index 3f9673d94da999746c2eba5a33de98ed1bbd4f68..261168607c9196899c83ef9cb388f22765dff873 100644 (file)
@@ -14,6 +14,8 @@
  * any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -59,7 +61,8 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type,
        if (report_enum->report_id_hash[id])
                return report_enum->report_id_hash[id];
 
-       if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
+       report = kzalloc(sizeof(struct hid_report), GFP_KERNEL);
+       if (!report)
                return NULL;
 
        if (id != 0)
@@ -90,8 +93,11 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
                return NULL;
        }
 
-       if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
-               + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
+       field = kzalloc((sizeof(struct hid_field) +
+                        usages * sizeof(struct hid_usage) +
+                        values * sizeof(unsigned)), GFP_KERNEL);
+       if (!field)
+               return NULL;
 
        field->index = report->maxfield++;
        report->field[field->index] = field;
@@ -172,10 +178,14 @@ static int close_collection(struct hid_parser *parser)
 
 static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
 {
+       struct hid_collection *collection = parser->device->collection;
        int n;
-       for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
-               if (parser->device->collection[parser->collection_stack[n]].type == type)
-                       return parser->device->collection[parser->collection_stack[n]].usage;
+
+       for (n = parser->collection_stack_ptr - 1; n >= 0; n--) {
+               unsigned index = parser->collection_stack[n];
+               if (collection[index].type == type)
+                       return collection[index].usage;
+       }
        return 0; /* we know nothing about this usage type */
 }
 
@@ -209,7 +219,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
        unsigned offset;
        int i;
 
-       if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
+       report = hid_register_report(parser->device, report_type, parser->global.report_id);
+       if (!report) {
                dbg_hid("hid_register_report failed\n");
                return -1;
        }
@@ -227,7 +238,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
 
        usages = max_t(int, parser->local.usage_index, parser->global.report_count);
 
-       if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
+       field = hid_register_field(report, usages, parser->global.report_count);
+       if (!field)
                return 0;
 
        field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
@@ -652,13 +664,12 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
                return -ENOMEM;
        device->rsize = size;
 
-       parser = vmalloc(sizeof(struct hid_parser));
+       parser = vzalloc(sizeof(struct hid_parser));
        if (!parser) {
                ret = -ENOMEM;
                goto err;
        }
 
-       memset(parser, 0, sizeof(struct hid_parser));
        parser->device = device;
 
        end = start + size;
@@ -672,7 +683,8 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
 
                if (dispatch_type[item.type](parser, &item)) {
                        dbg_hid("item %u %u %u %u parsing failed\n",
-                               item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
+                               item.format, (unsigned)item.size,
+                               (unsigned)item.type, (unsigned)item.tag);
                        goto err;
                }
 
@@ -737,13 +749,14 @@ static u32 s32ton(__s32 value, unsigned n)
  * Search linux-kernel and linux-usb-devel archives for "hid-core extract".
  */
 
-static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
+static __u32 extract(const struct hid_device *hid, __u8 *report,
+                    unsigned offset, unsigned n)
 {
        u64 x;
 
        if (n > 32)
-               printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n",
-                               n, current->comm);
+               hid_warn(hid, "extract() called with n (%d) > 32! (%s)\n",
+                        n, current->comm);
 
        report += offset >> 3;  /* adjust byte index */
        offset &= 7;            /* now only need bit offset into one byte */
@@ -760,18 +773,19 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
  * endianness of register values by considering a register
  * a "cached" copy of the little endiad bit stream.
  */
-static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
+static void implement(const struct hid_device *hid, __u8 *report,
+                     unsigned offset, unsigned n, __u32 value)
 {
        u64 x;
        u64 m = (1ULL << n) - 1;
 
        if (n > 32)
-               printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n",
-                               n, current->comm);
+               hid_warn(hid, "%s() called with n (%d) > 32! (%s)\n",
+                        __func__, n, current->comm);
 
        if (value > m)
-               printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n",
-                               value, current->comm);
+               hid_warn(hid, "%s() called with too large value %d! (%s)\n",
+                        __func__, value, current->comm);
        WARN_ON(value > m);
        value &= m;
 
@@ -788,7 +802,7 @@ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u3
  * Search an array for a value.
  */
 
-static __inline__ int search(__s32 *array, __s32 value, unsigned n)
+static int search(__s32 *array, __s32 value, unsigned n)
 {
        while (n--) {
                if (*array++ == value)
@@ -887,18 +901,22 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
        __s32 max = field->logical_maximum;
        __s32 *value;
 
-       if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
+       value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC);
+       if (!value)
                return;
 
        for (n = 0; n < count; n++) {
 
-                       value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
-                                                   extract(data, offset + n * size, size);
+               value[n] = min < 0 ?
+                       snto32(extract(hid, data, offset + n * size, size),
+                              size) :
+                       extract(hid, data, offset + n * size, size);
 
-                       if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */
-                           && value[n] >= min && value[n] <= max
-                           && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
-                               goto exit;
+               /* Ignore report if ErrorRollOver */
+               if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
+                   value[n] >= min && value[n] <= max &&
+                   field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
+                       goto exit;
        }
 
        for (n = 0; n < count; n++) {
@@ -928,7 +946,8 @@ exit:
  * Output the field into the report.
  */
 
-static void hid_output_field(struct hid_field *field, __u8 *data)
+static void hid_output_field(const struct hid_device *hid,
+                            struct hid_field *field, __u8 *data)
 {
        unsigned count = field->report_count;
        unsigned offset = field->report_offset;
@@ -937,9 +956,11 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
 
        for (n = 0; n < count; n++) {
                if (field->logical_minimum < 0) /* signed values */
-                       implement(data, offset + n * size, size, s32ton(field->value[n], size));
+                       implement(hid, data, offset + n * size, size,
+                                 s32ton(field->value[n], size));
                else                            /* unsigned values */
-                       implement(data, offset + n * size, size, field->value[n]);
+                       implement(hid, data, offset + n * size, size,
+                                 field->value[n]);
        }
 }
 
@@ -956,7 +977,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
 
        memset(data, 0, ((report->size - 1) >> 3) + 1);
        for (n = 0; n < report->maxfield; n++)
-               hid_output_field(report->field[n], data);
+               hid_output_field(report->device, report->field[n], data);
 }
 EXPORT_SYMBOL_GPL(hid_output_report);
 
@@ -1169,8 +1190,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
                hdev->claimed |= HID_CLAIMED_HIDRAW;
 
        if (!hdev->claimed) {
-               dev_err(&hdev->dev, "claimed by neither input, hiddev nor "
-                               "hidraw\n");
+               hid_err(hdev, "claimed by neither input, hiddev nor hidraw\n");
                return -ENODEV;
        }
 
@@ -1210,9 +1230,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
                bus = "<UNKNOWN>";
        }
 
-       dev_info(&hdev->dev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
-                       buf, bus, hdev->version >> 8, hdev->version & 0xff,
-                       type, hdev->name, hdev->phys);
+       hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
+                buf, bus, hdev->version >> 8, hdev->version & 0xff,
+                type, hdev->name, hdev->phys);
 
        return 0;
 }
@@ -1230,7 +1250,7 @@ void hid_disconnect(struct hid_device *hdev)
 EXPORT_SYMBOL_GPL(hid_disconnect);
 
 /* a list of devices for which there is a specialized driver on HID bus */
-static const struct hid_device_id hid_blacklist[] = {
+static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
        { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
@@ -1276,6 +1296,12 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -1292,6 +1318,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
@@ -1304,6 +1331,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
        { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
@@ -1372,6 +1400,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
@@ -1499,9 +1528,9 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv)
        if (!hid_match_device(hdev, hdrv))
                return 0;
 
-       /* generic wants all non-blacklisted */
+       /* generic wants all that don't have specialized driver */
        if (!strncmp(hdrv->name, "generic-", 8))
-               return !hid_match_id(hdev, hid_blacklist);
+               return !hid_match_id(hdev, hid_have_special_driver);
 
        return 1;
 }
@@ -1761,6 +1790,12 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { }
@@ -1952,12 +1987,12 @@ static int __init hid_init(void)
        int ret;
 
        if (hid_debug)
-               printk(KERN_WARNING "HID: hid_debug is now used solely for parser and driver debugging.\n"
-                               "HID: debugfs is now used for inspecting the device (report descriptor, reports)\n");
+               pr_warn("hid_debug is now used solely for parser and driver debugging.\n"
+                       "debugfs is now used for inspecting the device (report descriptor, reports)\n");
 
        ret = bus_register(&hid_bus_type);
        if (ret) {
-               printk(KERN_ERR "HID: can't register hid bus\n");
+               pr_err("can't register hid bus\n");
                goto err;
        }
 
index 4cd0e2345991bd6faf5055286b23a8c093c66ac5..2f0be4c66af72f356fb2cedf144c1d45375493a7 100644 (file)
@@ -107,13 +107,13 @@ static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
index 75c5e23d09d2074d1869731722b89615cb896607..555382fc74179c8bb5e2c3bc3deffe9653132b36 100644 (file)
@@ -26,6 +26,8 @@
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/sched.h>
@@ -393,7 +395,7 @@ char *hid_resolv_usage(unsigned usage, struct seq_file *f) {
 
        buf = resolv_usage_page(usage >> 16, f);
        if (IS_ERR(buf)) {
-               printk(KERN_ERR "error allocating HID debug buffer\n");
+               pr_err("error allocating HID debug buffer\n");
                return NULL;
        }
 
index 968b04f9b796cf8208c5839fb8c1f61fbc7467ee..afcf3d67eb024683cc43e11f5325184ce8235871 100644 (file)
@@ -96,18 +96,18 @@ static int drff_init(struct hid_device *hid)
        int error;
 
        if (list_empty(report_list)) {
-               dev_err(&hid->dev, "no output reports found\n");
+               hid_err(hid, "no output reports found\n");
                return -ENODEV;
        }
 
        report = list_first_entry(report_list, struct hid_report, list);
        if (report->maxfield < 1) {
-               dev_err(&hid->dev, "no fields in the report\n");
+               hid_err(hid, "no fields in the report\n");
                return -ENODEV;
        }
 
        if (report->field[0]->report_count < 7) {
-               dev_err(&hid->dev, "not enough values in the field\n");
+               hid_err(hid, "not enough values in the field\n");
                return -ENODEV;
        }
 
@@ -133,8 +133,8 @@ static int drff_init(struct hid_device *hid)
        drff->report->field[0]->value[6] = 0x00;
        usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
 
-       dev_info(&hid->dev, "Force Feedback for DragonRise Inc. game "
-              "controllers by Richard Walmsley <richwalm@gmail.com>\n");
+       hid_info(hid, "Force Feedback for DragonRise Inc. "
+                "game controllers by Richard Walmsley <richwalm@gmail.com>\n");
 
        return 0;
 }
@@ -153,13 +153,13 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err;
        }
 
index 8fbff2358eb663b7e3ee00bca9aa3e903fa0e9f6..03bee1970d70a076cf98e66f2a5ccdd1c4c2139c 100644 (file)
@@ -200,7 +200,7 @@ static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL);
        if (!td) {
-               dev_err(&hdev->dev, "cannot allocate eGalax data\n");
+               hid_err(hdev, "cannot allocate eGalax data\n");
                return -ENOMEM;
        }
        hid_set_drvdata(hdev, td);
index 6e31f305397d1b60bb750efd1f81f17724e175a8..79d0c61e7214a0057ce03b781bb8b40c6cbaaf16 100644 (file)
@@ -24,8 +24,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
        if (*rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) {
-               dev_info(&hdev->dev, "Fixing up Elecom BM084 "
-                               "report descriptor.\n");
+               hid_info(hdev, "Fixing up Elecom BM084 report descriptor\n");
                rdesc[47] = 0x00;
        }
     return rdesc;
diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c
new file mode 100644 (file)
index 0000000..81877c6
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *  Force feedback support for EMS Trio Linker Plus II
+ *
+ *  Copyright (c) 2010 Ignaz Forster <ignaz.forster@gmx.de>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+
+struct emsff_device {
+       struct hid_report *report;
+};
+
+static int emsff_play(struct input_dev *dev, void *data,
+                        struct ff_effect *effect)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct emsff_device *emsff = data;
+       int weak, strong;
+
+       weak = effect->u.rumble.weak_magnitude;
+       strong = effect->u.rumble.strong_magnitude;
+
+       dbg_hid("called with 0x%04x 0x%04x\n", strong, weak);
+
+       weak = weak * 0xff / 0xffff;
+       strong = strong * 0xff / 0xffff;
+
+       emsff->report->field[0]->value[1] = weak;
+       emsff->report->field[0]->value[2] = strong;
+
+       dbg_hid("running with 0x%02x 0x%02x\n", strong, weak);
+       usbhid_submit_report(hid, emsff->report, USB_DIR_OUT);
+
+       return 0;
+}
+
+static int emsff_init(struct hid_device *hid)
+{
+       struct emsff_device *emsff;
+       struct hid_report *report;
+       struct hid_input *hidinput = list_first_entry(&hid->inputs,
+                                               struct hid_input, list);
+       struct list_head *report_list =
+                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct input_dev *dev = hidinput->input;
+       int error;
+
+       if (list_empty(report_list)) {
+               hid_err(hid, "no output reports found\n");
+               return -ENODEV;
+       }
+
+       report = list_first_entry(report_list, struct hid_report, list);
+       if (report->maxfield < 1) {
+               hid_err(hid, "no fields in the report\n");
+               return -ENODEV;
+       }
+
+       if (report->field[0]->report_count < 7) {
+               hid_err(hid, "not enough values in the field\n");
+               return -ENODEV;
+       }
+
+       emsff = kzalloc(sizeof(struct emsff_device), GFP_KERNEL);
+       if (!emsff)
+               return -ENOMEM;
+
+       set_bit(FF_RUMBLE, dev->ffbit);
+
+       error = input_ff_create_memless(dev, emsff, emsff_play);
+       if (error) {
+               kfree(emsff);
+               return error;
+       }
+
+       emsff->report = report;
+       emsff->report->field[0]->value[0] = 0x01;
+       emsff->report->field[0]->value[1] = 0x00;
+       emsff->report->field[0]->value[2] = 0x00;
+       emsff->report->field[0]->value[3] = 0x00;
+       emsff->report->field[0]->value[4] = 0x00;
+       emsff->report->field[0]->value[5] = 0x00;
+       emsff->report->field[0]->value[6] = 0x00;
+       usbhid_submit_report(hid, emsff->report, USB_DIR_OUT);
+
+       hid_info(hid, "force feedback for EMS based devices by Ignaz Forster <ignaz.forster@gmx.de>\n");
+
+       return 0;
+}
+
+static int ems_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               hid_err(hdev, "parse failed\n");
+               goto err;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+       if (ret) {
+               hid_err(hdev, "hw start failed\n");
+               goto err;
+       }
+
+       emsff_init(hdev);
+
+       return 0;
+err:
+       return ret;
+}
+
+static const struct hid_device_id ems_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_EMS, 0x118) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, ems_devices);
+
+static struct hid_driver ems_driver = {
+       .name = "hkems",
+       .id_table = ems_devices,
+       .probe = ems_probe,
+};
+
+static int ems_init(void)
+{
+       return hid_register_driver(&ems_driver);
+}
+
+static void ems_exit(void)
+{
+       hid_unregister_driver(&ems_driver);
+}
+
+module_init(ems_init);
+module_exit(ems_exit);
+MODULE_LICENSE("GPL");
+
index 88dfcf49a5d72b0f2e61d9e07557c1a2e6a8cd55..279ba530003cc5dcbcdff46256f18d2e5f112b22 100644 (file)
@@ -87,7 +87,7 @@ static int gaff_init(struct hid_device *hid)
        int error;
 
        if (list_empty(report_list)) {
-               dev_err(&hid->dev, "no output reports found\n");
+               hid_err(hid, "no output reports found\n");
                return -ENODEV;
        }
 
@@ -95,12 +95,12 @@ static int gaff_init(struct hid_device *hid)
 
        report = list_entry(report_ptr, struct hid_report, list);
        if (report->maxfield < 1) {
-               dev_err(&hid->dev, "no fields in the report\n");
+               hid_err(hid, "no fields in the report\n");
                return -ENODEV;
        }
 
        if (report->field[0]->report_count < 6) {
-               dev_err(&hid->dev, "not enough values in the field\n");
+               hid_err(hid, "not enough values in the field\n");
                return -ENODEV;
        }
 
@@ -128,8 +128,7 @@ static int gaff_init(struct hid_device *hid)
 
        usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
 
-       dev_info(&hid->dev, "Force Feedback for GreenAsia 0x12"
-              " devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n");
+       hid_info(hid, "Force Feedback for GreenAsia 0x12 devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n");
 
        return 0;
 }
@@ -148,13 +147,13 @@ static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err;
        }
 
index 8e11af86b0144f6107ecf372d68cd11aae0e1567..f65cace777299933ba3b4b1eda2190f36d53c612 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI   0x0236
 #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO    0x0237
 #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS    0x0238
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI   0x023f
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO    0x0240
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS    0x0241
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI  0x0242
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO   0x0243
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS   0x0244
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI  0x0239
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO   0x023a
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
 #define USB_VENDOR_ID_CHICONY          0x04f2
 #define USB_DEVICE_ID_CHICONY_TACTICAL_PAD     0x0418
 #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH      0xb19d
+#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
 
 #define USB_VENDOR_ID_CIDC             0x1677
 
 #define USB_VENDOR_ID_ELO              0x04E7
 #define USB_DEVICE_ID_ELO_TS2700       0x0020
 
+#define USB_VENDOR_ID_EMS              0x2006
+#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
+
 #define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
 
 #define USB_VENDOR_ID_ROCCAT           0x1e7d
 #define USB_DEVICE_ID_ROCCAT_KONE      0x2ced
+#define USB_DEVICE_ID_ROCCAT_KONEPLUS  0x2d51
 #define USB_DEVICE_ID_ROCCAT_PYRA_WIRED        0x2c24
 #define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS     0x2cf6
 
index d8d372bae3cc16d3d5f43dda55ee89214d05d2d4..e60fdb88101fd7e6213c015e0526523050874ccc 100644 (file)
@@ -319,21 +319,21 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 
                switch (field->application) {
                case HID_GD_MOUSE:
-               case HID_GD_POINTER:  code += 0x110; break;
+               case HID_GD_POINTER:  code += BTN_MOUSE; break;
                case HID_GD_JOYSTICK:
                                if (code <= 0xf)
                                        code += BTN_JOYSTICK;
                                else
                                        code += BTN_TRIGGER_HAPPY;
                                break;
-               case HID_GD_GAMEPAD:  code += 0x130; break;
+               case HID_GD_GAMEPAD:  code += BTN_GAMEPAD; break;
                default:
                        switch (field->physical) {
                        case HID_GD_MOUSE:
-                       case HID_GD_POINTER:  code += 0x110; break;
-                       case HID_GD_JOYSTICK: code += 0x120; break;
-                       case HID_GD_GAMEPAD:  code += 0x130; break;
-                       default:              code += 0x100;
+                       case HID_GD_POINTER:  code += BTN_MOUSE; break;
+                       case HID_GD_JOYSTICK: code += BTN_JOYSTICK; break;
+                       case HID_GD_GAMEPAD:  code += BTN_GAMEPAD; break;
+                       default:              code += BTN_MISC;
                        }
                }
 
@@ -817,14 +817,14 @@ static int hidinput_open(struct input_dev *dev)
 {
        struct hid_device *hid = input_get_drvdata(dev);
 
-       return hid->ll_driver->open(hid);
+       return hid_hw_open(hid);
 }
 
 static void hidinput_close(struct input_dev *dev)
 {
        struct hid_device *hid = input_get_drvdata(dev);
 
-       hid->ll_driver->close(hid);
+       hid_hw_close(hid);
 }
 
 /*
@@ -871,7 +871,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                                if (!hidinput || !input_dev) {
                                        kfree(hidinput);
                                        input_free_device(input_dev);
-                                       err_hid("Out of memory during hid input probe");
+                                       hid_err(hid, "Out of memory during hid input probe\n");
                                        goto out_unwind;
                                }
 
index 817247ee006c88119405e0df8c48413f68c2b1eb..f2ba9efc3a53fb88ccb9db61e84f1802ef9fa9cb 100644 (file)
@@ -32,8 +32,8 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
                rdesc[71] == 0x75 && rdesc[72] == 0x08 &&
                rdesc[73] == 0x95 && rdesc[74] == 0x01) {
-               dev_info(&hdev->dev, "fixing up Kye/Genius Ergo Mouse report "
-                               "descriptor\n");
+               hid_info(hdev,
+                        "fixing up Kye/Genius Ergo Mouse report descriptor\n");
                rdesc[62] = 0x09;
                rdesc[64] = 0x04;
                rdesc[66] = 0x07;
index b629fba5a05757c5743fc9cfa06d69280b3173ef..aef4104da1417066930e6ac7db9c6cdb327f4b83 100644 (file)
@@ -53,23 +53,22 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 
        if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
                        rdesc[84] == 0x8c && rdesc[85] == 0x02) {
-               dev_info(&hdev->dev, "fixing up Logitech keyboard report "
-                               "descriptor\n");
+               hid_info(hdev,
+                        "fixing up Logitech keyboard report descriptor\n");
                rdesc[84] = rdesc[89] = 0x4d;
                rdesc[85] = rdesc[90] = 0x10;
        }
        if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
                        rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
                        rdesc[49] == 0x81 && rdesc[50] == 0x06) {
-               dev_info(&hdev->dev, "fixing up rel/abs in Logitech "
-                               "report descriptor\n");
+               hid_info(hdev,
+                        "fixing up rel/abs in Logitech report descriptor\n");
                rdesc[33] = rdesc[50] = 0x02;
        }
        if ((quirks & LG_FF4) && *rsize >= 101 &&
                        rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
                        rdesc[47] == 0x05 && rdesc[48] == 0x09) {
-               dev_info(&hdev->dev, "fixing up Logitech Speed Force Wireless "
-                       "button descriptor\n");
+               hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n");
                rdesc[41] = 0x05;
                rdesc[42] = 0x09;
                rdesc[47] = 0x95;
@@ -288,7 +287,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
@@ -297,7 +296,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_hw_start(hdev, connect_mask);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
index 4258253c36b35d9fa1f4530c03e5ab6da23f0f2a..3c31bc650e5d6e8b957618fb9d9dd306f677c22f 100644 (file)
@@ -72,18 +72,18 @@ int lg2ff_init(struct hid_device *hid)
        int error;
 
        if (list_empty(report_list)) {
-               dev_err(&hid->dev, "no output report found\n");
+               hid_err(hid, "no output report found\n");
                return -ENODEV;
        }
 
        report = list_entry(report_list->next, struct hid_report, list);
 
        if (report->maxfield < 1) {
-               dev_err(&hid->dev, "output report is empty\n");
+               hid_err(hid, "output report is empty\n");
                return -ENODEV;
        }
        if (report->field[0]->report_count < 7) {
-               dev_err(&hid->dev, "not enough values in the field\n");
+               hid_err(hid, "not enough values in the field\n");
                return -ENODEV;
        }
 
@@ -110,8 +110,7 @@ int lg2ff_init(struct hid_device *hid)
 
        usbhid_submit_report(hid, report, USB_DIR_OUT);
 
-       dev_info(&hid->dev, "Force feedback for Logitech RumblePad/Rumblepad 2 by "
-              "Anssi Hannula <anssi.hannula@gmail.com>\n");
+       hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula <anssi.hannula@gmail.com>\n");
 
        return 0;
 }
index 4002832ee4af6ce6f6454b387b78b9d13142f2e7..f98644c26c1dfc2ccc181a23fee0d94b6c6e03ef 100644 (file)
@@ -141,20 +141,20 @@ int lg3ff_init(struct hid_device *hid)
 
        /* Find the report to use */
        if (list_empty(report_list)) {
-               err_hid("No output report found");
+               hid_err(hid, "No output report found\n");
                return -1;
        }
 
        /* Check that the report looks ok */
        report = list_entry(report_list->next, struct hid_report, list);
        if (!report) {
-               err_hid("NULL output report");
+               hid_err(hid, "NULL output report\n");
                return -1;
        }
 
        field = report->field[0];
        if (!field) {
-               err_hid("NULL field");
+               hid_err(hid, "NULL field\n");
                return -1;
        }
 
@@ -169,8 +169,7 @@ int lg3ff_init(struct hid_device *hid)
        if (test_bit(FF_AUTOCENTER, dev->ffbit))
                dev->ff->set_autocenter = hid_lg3ff_set_autocenter;
 
-       dev_info(&hid->dev, "Force feedback for Logitech Flight System G940 by "
-                       "Gary Stein <LordCnidarian@gmail.com>\n");
+       hid_info(hid, "Force feedback for Logitech Flight System G940 by Gary Stein <LordCnidarian@gmail.com>\n");
        return 0;
 }
 
index 7eef5a2ce9487c5d0d291a368c15b9a54b230a14..fa550c8e1d1bc639bd3e9c34a299903391bca44a 100644 (file)
@@ -101,20 +101,20 @@ int lg4ff_init(struct hid_device *hid)
 
        /* Find the report to use */
        if (list_empty(report_list)) {
-               err_hid("No output report found");
+               hid_err(hid, "No output report found\n");
                return -1;
        }
 
        /* Check that the report looks ok */
        report = list_entry(report_list->next, struct hid_report, list);
        if (!report) {
-               err_hid("NULL output report");
+               hid_err(hid, "NULL output report\n");
                return -1;
        }
 
        field = report->field[0];
        if (!field) {
-               err_hid("NULL field");
+               hid_err(hid, "NULL field\n");
                return -1;
        }
 
@@ -129,8 +129,7 @@ int lg4ff_init(struct hid_device *hid)
        if (test_bit(FF_AUTOCENTER, dev->ffbit))
                dev->ff->set_autocenter = hid_lg4ff_set_autocenter;
 
-       dev_info(&hid->dev, "Force feedback for Logitech Speed Force Wireless by "
-                       "Simon Wood <simon@mungewell.org>\n");
+       hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n");
        return 0;
 }
 
index 61142b76a9b19fe90826dfda870d7717d7f36f4b..90d0ef2c92be9030664d348e6f59ad05af7c7dad 100644 (file)
@@ -27,6 +27,8 @@
  * e-mail - mail your message to <johann.deneux@it.uu.se>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/hid.h>
@@ -146,7 +148,7 @@ int lgff_init(struct hid_device* hid)
 
        /* Find the report to use */
        if (list_empty(report_list)) {
-               err_hid("No output report found");
+               hid_err(hid, "No output report found\n");
                return -1;
        }
 
@@ -154,7 +156,7 @@ int lgff_init(struct hid_device* hid)
        report = list_entry(report_list->next, struct hid_report, list);
        field = report->field[0];
        if (!field) {
-               err_hid("NULL field");
+               hid_err(hid, "NULL field\n");
                return -1;
        }
 
@@ -176,7 +178,7 @@ int lgff_init(struct hid_device* hid)
        if ( test_bit(FF_AUTOCENTER, dev->ffbit) )
                dev->ff->set_autocenter = hid_lgff_set_autocenter;
 
-       printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
+       pr_info("Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
 
        return 0;
 }
index e6dc151716643f0997e4eac4dc3d079c368dd15f..698e6459fd0b3cab629e9696b44b0ae10e63ce70 100644 (file)
@@ -12,6 +12,8 @@
  * any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
@@ -433,6 +435,11 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
        if (!msc->input)
                msc->input = hi->input;
 
+       /* Magic Trackpad does not give relative data after switching to MT */
+       if (hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD &&
+           field->flags & HID_MAIN_ITEM_RELATIVE)
+               return -1;
+
        return 0;
 }
 
@@ -446,7 +453,7 @@ static int magicmouse_probe(struct hid_device *hdev,
 
        msc = kzalloc(sizeof(*msc), GFP_KERNEL);
        if (msc == NULL) {
-               dev_err(&hdev->dev, "can't alloc magicmouse descriptor\n");
+               hid_err(hdev, "can't alloc magicmouse descriptor\n");
                return -ENOMEM;
        }
 
@@ -459,13 +466,13 @@ static int magicmouse_probe(struct hid_device *hdev,
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "magicmouse hid parse failed\n");
+               hid_err(hdev, "magicmouse hid parse failed\n");
                goto err_free;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
-               dev_err(&hdev->dev, "magicmouse hw start failed\n");
+               hid_err(hdev, "magicmouse hw start failed\n");
                goto err_free;
        }
 
@@ -486,7 +493,7 @@ static int magicmouse_probe(struct hid_device *hdev,
        }
 
        if (!report) {
-               dev_err(&hdev->dev, "unable to register touch report\n");
+               hid_err(hdev, "unable to register touch report\n");
                ret = -ENOMEM;
                goto err_stop_hw;
        }
@@ -495,8 +502,7 @@ static int magicmouse_probe(struct hid_device *hdev,
        ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
                        HID_FEATURE_REPORT);
        if (ret != sizeof(feature)) {
-               dev_err(&hdev->dev, "unable to request touch data (%d)\n",
-                               ret);
+               hid_err(hdev, "unable to request touch data (%d)\n", ret);
                goto err_stop_hw;
        }
 
@@ -540,7 +546,7 @@ static int __init magicmouse_init(void)
 
        ret = hid_register_driver(&magicmouse_driver);
        if (ret)
-               printk(KERN_ERR "can't register magicmouse driver\n");
+               pr_err("can't register magicmouse driver\n");
 
        return ret;
 }
index dc618c33d0a2631cb9bb0085a06f6504cf6b2513..0f6fc54dc196f71130765c14c5b8d8fc2093d155 100644 (file)
@@ -40,8 +40,7 @@ static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 
        if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 &&
                        rdesc[559] == 0x29) {
-               dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver "
-                               "Model 1028 report descriptor\n");
+               hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
                rdesc[557] = 0x35;
                rdesc[559] = 0x45;
        }
@@ -155,14 +154,14 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ?
                                HID_CONNECT_HIDINPUT_FORCE : 0));
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
index c95c31e2d86923bfc2b5fd4374f4f406a005d860..dedf757781ae1c9f907ad1e4d390ddc4b9c997cc 100644 (file)
@@ -26,8 +26,7 @@ static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
        if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
-               dev_info(&hdev->dev, "fixing up button/consumer in HID report "
-                               "descriptor\n");
+               hid_info(hdev, "fixing up button/consumer in HID report descriptor\n");
                rdesc[30] = 0x0c;
        }
        return rdesc;
index ac5421d568f151cd6937f33244740d9f9759fedb..9fb050ce6f04fc8ee82f8c2f78bb07a2bab440ee 100644 (file)
@@ -90,6 +90,10 @@ static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        case 0xff000000:
                /* ignore HID features */
                return -1;
+
+       case HID_UP_BUTTON:
+               /* ignore buttons */
+               return -1;
        }
 
        return 0;
@@ -199,7 +203,7 @@ static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
        if (!td) {
-               dev_err(&hdev->dev, "cannot allocate MosArt data\n");
+               hid_err(hdev, "cannot allocate MosArt data\n");
                return -ENOMEM;
        }
        td->valid = false;
@@ -230,6 +234,19 @@ static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
        return ret;
 }
 
+#ifdef CONFIG_PM
+static int mosart_reset_resume(struct hid_device *hdev)
+{
+       struct hid_report_enum *re = hdev->report_enum
+                                               + HID_FEATURE_REPORT;
+       struct hid_report *r = re->report_id_hash[7];
+
+       r->field[0]->value[0] = 0x02;
+       usbhid_submit_report(hdev, r, USB_DIR_OUT);
+       return 0;
+}
+#endif
+
 static void mosart_remove(struct hid_device *hdev)
 {
        hid_hw_stop(hdev);
@@ -258,6 +275,9 @@ static struct hid_driver mosart_driver = {
        .input_mapped = mosart_input_mapped,
        .usage_table = mosart_grabbed_usages,
        .event = mosart_event,
+#ifdef CONFIG_PM
+       .reset_resume = mosart_reset_resume,
+#endif
 };
 
 static int __init mosart_init(void)
index 69169efa1e16eee2653bdf11e28bd0684c2fd80d..beb403421e72e0efe30859c797ab2fc48fce40f5 100644 (file)
@@ -130,8 +130,7 @@ static void ntrig_report_version(struct hid_device *hdev)
        if (ret == 8) {
                ret = ntrig_version_string(&data[2], buf);
 
-               dev_info(&hdev->dev,
-                        "Firmware version: %s (%02x%02x %02x%02x)\n",
+               hid_info(hdev, "Firmware version: %s (%02x%02x %02x%02x)\n",
                         buf, data[2], data[3], data[4], data[5]);
        }
 
@@ -831,7 +830,7 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
        if (!nd) {
-               dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
+               hid_err(hdev, "cannot allocate N-Trig data\n");
                return -ENOMEM;
        }
 
@@ -850,13 +849,13 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
index 2e79716dca31e424243e6d6ca4d7dba78e4e0702..e90edfc63051bd34560c3e99d2df13308a1cb454 100644 (file)
@@ -23,8 +23,7 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
        if (*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) {
-               dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 "
-                               "report descriptor.\n");
+               hid_info(hdev, "Fixing up Ortek WKB-2000 report descriptor\n");
                rdesc[55] = 0x92;
        }
        return rdesc;
index 308d6ae48a3e4b5baa10a402eae47d00acfd7cfb..f1ea3ff8a98d8a26eb08b3a73ebe82e4b3047805 100644 (file)
@@ -29,8 +29,7 @@ static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
                        rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
                        rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
-               dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report "
-                               "descriptor\n");
+               hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");
                rdesc[60] = 0xfa;
                rdesc[40] = 0xfa;
        }
@@ -77,13 +76,13 @@ static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
index bc2e0774062864667ca92c52e3b4e7a23d923f53..de9cf21b3494c39d7a105f75a90078ebfe8b145e 100644 (file)
@@ -253,7 +253,7 @@ static struct hid_report *picolcd_report(int id, struct hid_device *hdev, int di
                if (report->id == id)
                        return report;
        }
-       dev_warn(&hdev->dev, "No report with id 0x%x found\n", id);
+       hid_warn(hdev, "No report with id 0x%x found\n", id);
        return NULL;
 }
 
@@ -1329,7 +1329,7 @@ static int picolcd_check_version(struct hid_device *hdev)
 
        verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
        if (!verinfo) {
-               dev_err(&hdev->dev, "no version response from PicoLCD");
+               hid_err(hdev, "no version response from PicoLCD\n");
                return -ENODEV;
        }
 
@@ -1337,14 +1337,14 @@ static int picolcd_check_version(struct hid_device *hdev)
                data->version[0] = verinfo->raw_data[1];
                data->version[1] = verinfo->raw_data[0];
                if (data->status & PICOLCD_BOOTLOADER) {
-                       dev_info(&hdev->dev, "PicoLCD, bootloader version %d.%d\n",
-                                       verinfo->raw_data[1], verinfo->raw_data[0]);
+                       hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
+                                verinfo->raw_data[1], verinfo->raw_data[0]);
                } else {
-                       dev_info(&hdev->dev, "PicoLCD, firmware version %d.%d\n",
-                                       verinfo->raw_data[1], verinfo->raw_data[0]);
+                       hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
+                                verinfo->raw_data[1], verinfo->raw_data[0]);
                }
        } else {
-               dev_err(&hdev->dev, "confused, got unexpected version response from PicoLCD\n");
+               hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
                ret = -EINVAL;
        }
        kfree(verinfo);
@@ -1544,7 +1544,7 @@ static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
 
        /* prepare buffer with info about what we want to read (addr & len) */
        raw_data[0] = *off & 0xff;
-       raw_data[1] = (*off >> 8) && 0xff;
+       raw_data[1] = (*off >> 8) & 0xff;
        raw_data[2] = s < 20 ? s : 20;
        if (*off + raw_data[2] > 0xff)
                raw_data[2] = 0x100 - *off;
@@ -1583,7 +1583,7 @@ static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
 
        memset(raw_data, 0, sizeof(raw_data));
        raw_data[0] = *off & 0xff;
-       raw_data[1] = (*off >> 8) && 0xff;
+       raw_data[1] = (*off >> 8) & 0xff;
        raw_data[2] = s < 20 ? s : 20;
        if (*off + raw_data[2] > 0xff)
                raw_data[2] = 0x100 - *off;
@@ -1867,6 +1867,7 @@ static void picolcd_debug_out_report(struct picolcd_data *data,
                        report->id, raw_size);
        hid_debug_event(hdev, buff);
        if (raw_size + 5 > sizeof(raw_data)) {
+               kfree(buff);
                hid_debug_event(hdev, " TOO BIG\n");
                return;
        } else {
@@ -2328,8 +2329,7 @@ static void picolcd_init_devfs(struct picolcd_data *data,
                        (flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),
                        hdev->debug_dir, data, &picolcd_debug_flash_fops);
        } else if (flash_r || flash_w)
-               dev_warn(&hdev->dev, "Unexpected FLASH access reports, "
-                               "please submit rdesc for review\n");
+               hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n");
 }
 
 static void picolcd_exit_devfs(struct picolcd_data *data)
@@ -2457,13 +2457,13 @@ static int picolcd_init_keys(struct picolcd_data *data,
                return -ENODEV;
        if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
                        report->field[0]->report_size != 8) {
-               dev_err(&hdev->dev, "unsupported KEY_STATE report");
+               hid_err(hdev, "unsupported KEY_STATE report\n");
                return -EINVAL;
        }
 
        idev = input_allocate_device();
        if (idev == NULL) {
-               dev_err(&hdev->dev, "failed to allocate input device");
+               hid_err(hdev, "failed to allocate input device\n");
                return -ENOMEM;
        }
        input_set_drvdata(idev, hdev);
@@ -2485,7 +2485,7 @@ static int picolcd_init_keys(struct picolcd_data *data,
                input_set_capability(idev, EV_KEY, data->keycode[i]);
        error = input_register_device(idev);
        if (error) {
-               dev_err(&hdev->dev, "error registering the input device");
+               hid_err(hdev, "error registering the input device\n");
                input_free_device(idev);
                return error;
        }
@@ -2522,9 +2522,8 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
                return error;
 
        if (data->version[0] != 0 && data->version[1] != 3)
-               dev_info(&hdev->dev, "Device with untested firmware revision, "
-                               "please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
-                               dev_name(&hdev->dev));
+               hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
+                        dev_name(&hdev->dev));
 
        /* Setup keypad input device */
        error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
@@ -2581,9 +2580,8 @@ static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data
                return error;
 
        if (data->version[0] != 1 && data->version[1] != 0)
-               dev_info(&hdev->dev, "Device with untested bootloader revision, "
-                               "please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
-                               dev_name(&hdev->dev));
+               hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
+                        dev_name(&hdev->dev));
 
        picolcd_init_devfs(data, NULL, NULL,
                        picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
@@ -2605,7 +2603,7 @@ static int picolcd_probe(struct hid_device *hdev,
         */
        data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
        if (data == NULL) {
-               dev_err(&hdev->dev, "can't allocate space for Minibox PicoLCD device data\n");
+               hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
                error = -ENOMEM;
                goto err_no_cleanup;
        }
@@ -2621,7 +2619,7 @@ static int picolcd_probe(struct hid_device *hdev,
        /* Parse the device reports and start it up */
        error = hid_parse(hdev);
        if (error) {
-               dev_err(&hdev->dev, "device report parse failed\n");
+               hid_err(hdev, "device report parse failed\n");
                goto err_cleanup_data;
        }
 
@@ -2631,25 +2629,25 @@ static int picolcd_probe(struct hid_device *hdev,
        error = hid_hw_start(hdev, 0);
        hdev->claimed = 0;
        if (error) {
-               dev_err(&hdev->dev, "hardware start failed\n");
+               hid_err(hdev, "hardware start failed\n");
                goto err_cleanup_data;
        }
 
-       error = hdev->ll_driver->open(hdev);
+       error = hid_hw_open(hdev);
        if (error) {
-               dev_err(&hdev->dev, "failed to open input interrupt pipe for key and IR events\n");
+               hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
                goto err_cleanup_hid_hw;
        }
 
        error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
        if (error) {
-               dev_err(&hdev->dev, "failed to create sysfs attributes\n");
+               hid_err(hdev, "failed to create sysfs attributes\n");
                goto err_cleanup_hid_ll;
        }
 
        error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
        if (error) {
-               dev_err(&hdev->dev, "failed to create sysfs attributes\n");
+               hid_err(hdev, "failed to create sysfs attributes\n");
                goto err_cleanup_sysfs1;
        }
 
@@ -2668,7 +2666,7 @@ err_cleanup_sysfs2:
 err_cleanup_sysfs1:
        device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
 err_cleanup_hid_ll:
-       hdev->ll_driver->close(hdev);
+       hid_hw_close(hdev);
 err_cleanup_hid_hw:
        hid_hw_stop(hdev);
 err_cleanup_data:
@@ -2699,7 +2697,7 @@ static void picolcd_remove(struct hid_device *hdev)
        picolcd_exit_devfs(data);
        device_remove_file(&hdev->dev, &dev_attr_operation_mode);
        device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
-       hdev->ll_driver->close(hdev);
+       hid_hw_close(hdev);
        hid_hw_stop(hdev);
        hid_set_drvdata(hdev, NULL);
 
@@ -2753,7 +2751,7 @@ static void __exit picolcd_exit(void)
 {
        hid_unregister_driver(&picolcd_driver);
 #ifdef CONFIG_HID_PICOLCD_FB
-       flush_scheduled_work();
+       flush_work_sync(&picolcd_fb_cleanup);
        WARN_ON(fb_pending);
 #endif
 }
index 9f41e2bd84839ed085ec15cc1c88fe6266371393..06e5300d43d2945ce9bf644d421bb1f3f8c0ac9c 100644 (file)
@@ -103,7 +103,7 @@ static int plff_init(struct hid_device *hid)
        */
 
        if (list_empty(report_list)) {
-               dev_err(&hid->dev, "no output reports found\n");
+               hid_err(hid, "no output reports found\n");
                return -ENODEV;
        }
 
@@ -112,14 +112,13 @@ static int plff_init(struct hid_device *hid)
                report_ptr = report_ptr->next;
 
                if (report_ptr == report_list) {
-                       dev_err(&hid->dev, "required output report is "
-                                       "missing\n");
+                       hid_err(hid, "required output report is missing\n");
                        return -ENODEV;
                }
 
                report = list_entry(report_ptr, struct hid_report, list);
                if (report->maxfield < 1) {
-                       dev_err(&hid->dev, "no fields in the report\n");
+                       hid_err(hid, "no fields in the report\n");
                        return -ENODEV;
                }
 
@@ -137,7 +136,7 @@ static int plff_init(struct hid_device *hid)
                        weak = &report->field[3]->value[0];
                        debug("detected 4-field device");
                } else {
-                       dev_err(&hid->dev, "not enough fields or values\n");
+                       hid_err(hid, "not enough fields or values\n");
                        return -ENODEV;
                }
 
@@ -164,8 +163,7 @@ static int plff_init(struct hid_device *hid)
                usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
        }
 
-       dev_info(&hid->dev, "Force feedback for PantherLord/GreenAsia "
-              "devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
+       hid_info(hid, "Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
 
        return 0;
 }
@@ -185,13 +183,13 @@ static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err;
        }
 
index 48eab84f53b5467acac72ad1ff57b2f3c79f4c9d..ab19f2905d27202a8a036a9a33eb4084bc9d5d80 100644 (file)
@@ -16,6 +16,8 @@
  * any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/usb.h>
@@ -130,7 +132,7 @@ static ssize_t store_channel(struct device *dev,
        return -EINVAL;
 }
 
-static DEVICE_ATTR(channel, S_IRUGO | S_IWUGO, show_channel,
+static DEVICE_ATTR(channel, S_IRUGO | S_IWUSR | S_IWGRP , show_channel,
                store_channel);
 
 static struct device_attribute *sysfs_device_attr_channel = {
@@ -169,7 +171,7 @@ static ssize_t store_sustain(struct device *dev,
        return -EINVAL;
 }
 
-static DEVICE_ATTR(sustain, S_IRUGO | S_IWUGO, show_sustain,
+static DEVICE_ATTR(sustain, S_IRUGO | S_IWUSR | S_IWGRP, show_sustain,
                store_sustain);
 
 static struct device_attribute *sysfs_device_attr_sustain = {
@@ -207,7 +209,7 @@ static ssize_t store_octave(struct device *dev,
        return -EINVAL;
 }
 
-static DEVICE_ATTR(octave, S_IRUGO | S_IWUGO, show_octave,
+static DEVICE_ATTR(octave, S_IRUGO | S_IWUSR | S_IWGRP, show_octave,
                store_octave);
 
 static struct device_attribute *sysfs_device_attr_octave = {
@@ -285,11 +287,11 @@ static int pcmidi_get_output_report(struct pcmidi_snd *pm)
                        continue;
 
                if (report->maxfield < 1) {
-                       dev_err(&hdev->dev, "output report is empty\n");
+                       hid_err(hdev, "output report is empty\n");
                        break;
                }
                if (report->field[0]->report_count != 2) {
-                       dev_err(&hdev->dev, "field count too low\n");
+                       hid_err(hdev, "field count too low\n");
                        break;
                }
                pm->pcmidi_report6 = report;
@@ -746,8 +748,8 @@ static __u8 *pk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        if (*rsize == 178 &&
              rdesc[111] == 0x06 && rdesc[112] == 0x00 &&
              rdesc[113] == 0xff) {
-               dev_info(&hdev->dev, "fixing up pc-midi keyboard report "
-                       "descriptor\n");
+               hid_info(hdev,
+                        "fixing up pc-midi keyboard report descriptor\n");
 
                rdesc[144] = 0x18; /* report 4: was 0x10 report count */
        }
@@ -805,7 +807,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        pk = kzalloc(sizeof(*pk), GFP_KERNEL);
        if (pk == NULL) {
-               dev_err(&hdev->dev, "prodikeys: can't alloc descriptor\n");
+               hid_err(hdev, "can't alloc descriptor\n");
                return -ENOMEM;
        }
 
@@ -813,8 +815,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        pm = kzalloc(sizeof(*pm), GFP_KERNEL);
        if (pm == NULL) {
-               dev_err(&hdev->dev,
-                       "prodikeys: can't alloc descriptor\n");
+               hid_err(hdev, "can't alloc descriptor\n");
                ret = -ENOMEM;
                goto err_free;
        }
@@ -827,7 +828,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "prodikeys: hid parse failed\n");
+               hid_err(hdev, "hid parse failed\n");
                goto err_free;
        }
 
@@ -837,7 +838,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
-               dev_err(&hdev->dev, "prodikeys: hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
@@ -896,7 +897,7 @@ static int pk_init(void)
 
        ret = hid_register_driver(&pk_driver);
        if (ret)
-               printk(KERN_ERR "can't register prodikeys driver\n");
+               pr_err("can't register prodikeys driver\n");
 
        return ret;
 }
index 54d3db50605b25e3beeecbccc9c0f96facc5e6dc..87a54df4d4ac5ea74afe904ecd782574bd66d6fd 100644 (file)
@@ -195,7 +195,7 @@ static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL);
        if (!td) {
-               dev_err(&hdev->dev, "cannot allocate Quanta Touch data\n");
+               hid_err(hdev, "cannot allocate Quanta Touch data\n");
                return -ENOMEM;
        }
        td->valid = false;
index f77695762cb567ea45c7f2ee2822127e7f1acc04..cbd8cc42e75ab38d203697f1752cbeabd09ad2c7 100644 (file)
 #include "hid-roccat.h"
 #include "hid-roccat-kone.h"
 
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+/* kone_class is used for creating sysfs attributes via roccat char device */
+static struct class *kone_class;
+
 static void kone_set_settings_checksum(struct kone_settings *settings)
 {
        uint16_t checksum = 0;
@@ -90,8 +95,7 @@ static int kone_check_write(struct usb_device *usb_dev)
                kfree(data);
                return 0;
        } else { /* unknown answer */
-               dev_err(&usb_dev->dev, "got retval %d when checking write\n",
-                               *data);
+               hid_err(usb_dev, "got retval %d when checking write\n", *data);
                kfree(data);
                return -EIO;
        }
@@ -262,7 +266,8 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
 static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
        struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
 
        if (off >= sizeof(struct kone_settings))
@@ -286,7 +291,8 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
 static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
        struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval = 0, difference;
@@ -319,10 +325,11 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
        return sizeof(struct kone_settings);
 }
 
-static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count, int number) {
-       struct device *dev = container_of(kobj, struct device, kobj);
+static ssize_t kone_sysfs_read_profilex(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count) {
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
        struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
 
        if (off >= sizeof(struct kone_profile))
@@ -332,47 +339,18 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
                count = sizeof(struct kone_profile) - off;
 
        mutex_lock(&kone->kone_lock);
-       memcpy(buf, ((char const *)&kone->profiles[number - 1]) + off, count);
+       memcpy(buf, ((char const *)&kone->profiles[*(uint *)(attr->private)]) + off, count);
        mutex_unlock(&kone->kone_lock);
 
        return count;
 }
 
-static ssize_t kone_sysfs_read_profile1(struct file *fp, struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count) {
-       return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 1);
-}
-
-static ssize_t kone_sysfs_read_profile2(struct file *fp, struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count) {
-       return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 2);
-}
-
-static ssize_t kone_sysfs_read_profile3(struct file *fp, struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count) {
-       return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 3);
-}
-
-static ssize_t kone_sysfs_read_profile4(struct file *fp, struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count) {
-       return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 4);
-}
-
-static ssize_t kone_sysfs_read_profile5(struct file *fp, struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count) {
-       return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 5);
-}
-
 /* Writes data only if different to stored data */
-static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count, int number) {
-       struct device *dev = container_of(kobj, struct device, kobj);
+static ssize_t kone_sysfs_write_profilex(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count) {
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
        struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        struct kone_profile *profile;
@@ -382,13 +360,14 @@ static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
        if (off != 0 || count != sizeof(struct kone_profile))
                return -EINVAL;
 
-       profile = &kone->profiles[number - 1];
+       profile = &kone->profiles[*(uint *)(attr->private)];
 
        mutex_lock(&kone->kone_lock);
        difference = memcmp(buf, profile, sizeof(struct kone_profile));
        if (difference) {
                retval = kone_set_profile(usb_dev,
-                               (struct kone_profile const *)buf, number);
+                               (struct kone_profile const *)buf,
+                               *(uint *)(attr->private) + 1);
                if (!retval)
                        memcpy(profile, buf, sizeof(struct kone_profile));
        }
@@ -400,47 +379,19 @@ static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
        return sizeof(struct kone_profile);
 }
 
-static ssize_t kone_sysfs_write_profile1(struct file *fp, struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count) {
-       return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 1);
-}
-
-static ssize_t kone_sysfs_write_profile2(struct file *fp, struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count) {
-       return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 2);
-}
-
-static ssize_t kone_sysfs_write_profile3(struct file *fp, struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count) {
-       return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 3);
-}
-
-static ssize_t kone_sysfs_write_profile4(struct file *fp, struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count) {
-       return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 4);
-}
-
-static ssize_t kone_sysfs_write_profile5(struct file *fp, struct kobject *kobj,
-               struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count) {
-       return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 5);
-}
-
 static ssize_t kone_sysfs_show_actual_profile(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+       struct kone_device *kone =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
        return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile);
 }
 
 static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+       struct kone_device *kone =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
        return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi);
 }
 
@@ -448,11 +399,15 @@ static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
 static ssize_t kone_sysfs_show_weight(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
-       struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+       struct kone_device *kone;
+       struct usb_device *usb_dev;
        int weight = 0;
        int retval;
 
+       dev = dev->parent->parent;
+       kone = hid_get_drvdata(dev_get_drvdata(dev));
+       usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
        mutex_lock(&kone->kone_lock);
        retval = kone_get_weight(usb_dev, &weight);
        mutex_unlock(&kone->kone_lock);
@@ -465,14 +420,16 @@ static ssize_t kone_sysfs_show_weight(struct device *dev,
 static ssize_t kone_sysfs_show_firmware_version(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+       struct kone_device *kone =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
        return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version);
 }
 
 static ssize_t kone_sysfs_show_tcu(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+       struct kone_device *kone =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
        return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.tcu);
 }
 
@@ -504,11 +461,15 @@ static int kone_tcu_command(struct usb_device *usb_dev, int number)
 static ssize_t kone_sysfs_set_tcu(struct device *dev,
                struct device_attribute *attr, char const *buf, size_t size)
 {
-       struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
-       struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+       struct kone_device *kone;
+       struct usb_device *usb_dev;
        int retval;
        unsigned long state;
 
+       dev = dev->parent->parent;
+       kone = hid_get_drvdata(dev_get_drvdata(dev));
+       usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
        retval = strict_strtoul(buf, 10, &state);
        if (retval)
                return retval;
@@ -556,7 +517,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
 
                retval = kone_set_settings(usb_dev, &kone->settings);
                if (retval) {
-                       dev_err(&usb_dev->dev, "couldn't set tcu state\n");
+                       hid_err(usb_dev, "couldn't set tcu state\n");
                        /*
                         * try to reread valid settings into buffer overwriting
                         * first error code
@@ -570,7 +531,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
 
        retval = size;
 exit_no_settings:
-       dev_err(&usb_dev->dev, "couldn't read settings\n");
+       hid_err(usb_dev, "couldn't read settings\n");
 exit_unlock:
        mutex_unlock(&kone->kone_lock);
        return retval;
@@ -579,18 +540,23 @@ exit_unlock:
 static ssize_t kone_sysfs_show_startup_profile(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+       struct kone_device *kone =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
        return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.startup_profile);
 }
 
 static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
                struct device_attribute *attr, char const *buf, size_t size)
 {
-       struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
-       struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+       struct kone_device *kone;
+       struct usb_device *usb_dev;
        int retval;
        unsigned long new_startup_profile;
 
+       dev = dev->parent->parent;
+       kone = hid_get_drvdata(dev_get_drvdata(dev));
+       usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
        retval = strict_strtoul(buf, 10, &new_startup_profile);
        if (retval)
                return retval;
@@ -617,160 +583,92 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
        return size;
 }
 
-/*
- * Read actual dpi settings.
- * Returns raw value for further processing. Refer to enum kone_polling_rates to
- * get real value.
- */
-static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL);
-
-static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL);
-
-/*
- * The mouse can be equipped with one of four supplied weights from 5 to 20
- * grams which are recognized and its value can be read out.
- * This returns the raw value reported by the mouse for easy evaluation by
- * software. Refer to enum kone_weights to get corresponding real weight.
- */
-static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL);
-
-/*
- * Prints firmware version stored in mouse as integer.
- * The raw value reported by the mouse is returned for easy evaluation, to get
- * the real version number the decimal point has to be shifted 2 positions to
- * the left. E.g. a value of 138 means 1.38.
- */
-static DEVICE_ATTR(firmware_version, 0440,
-               kone_sysfs_show_firmware_version, NULL);
-
-/*
- * Prints state of Tracking Control Unit as number where 0 = off and 1 = on
- * Writing 0 deactivates tcu and writing 1 calibrates and activates the tcu
- */
-static DEVICE_ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu);
-
-/* Prints and takes the number of the profile the mouse starts with */
-static DEVICE_ATTR(startup_profile, 0660,
-               kone_sysfs_show_startup_profile,
-               kone_sysfs_set_startup_profile);
-
-static struct attribute *kone_attributes[] = {
-               &dev_attr_actual_dpi.attr,
-               &dev_attr_actual_profile.attr,
-               &dev_attr_weight.attr,
-               &dev_attr_firmware_version.attr,
-               &dev_attr_tcu.attr,
-               &dev_attr_startup_profile.attr,
-               NULL
-};
-
-static struct attribute_group kone_attribute_group = {
-               .attrs = kone_attributes
-};
-
-static struct bin_attribute kone_settings_attr = {
-       .attr = { .name = "settings", .mode = 0660 },
-       .size = sizeof(struct kone_settings),
-       .read = kone_sysfs_read_settings,
-       .write = kone_sysfs_write_settings
-};
+static struct device_attribute kone_attributes[] = {
+       /*
+        * Read actual dpi settings.
+        * Returns raw value for further processing. Refer to enum
+        * kone_polling_rates to get real value.
+        */
+       __ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL),
+       __ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL),
 
-static struct bin_attribute kone_profile1_attr = {
-       .attr = { .name = "profile1", .mode = 0660 },
-       .size = sizeof(struct kone_profile),
-       .read = kone_sysfs_read_profile1,
-       .write = kone_sysfs_write_profile1
-};
+       /*
+        * The mouse can be equipped with one of four supplied weights from 5
+        * to 20 grams which are recognized and its value can be read out.
+        * This returns the raw value reported by the mouse for easy evaluation
+        * by software. Refer to enum kone_weights to get corresponding real
+        * weight.
+        */
+       __ATTR(weight, 0440, kone_sysfs_show_weight, NULL),
 
-static struct bin_attribute kone_profile2_attr = {
-       .attr = { .name = "profile2", .mode = 0660 },
-       .size = sizeof(struct kone_profile),
-       .read = kone_sysfs_read_profile2,
-       .write = kone_sysfs_write_profile2
-};
+       /*
+        * Prints firmware version stored in mouse as integer.
+        * The raw value reported by the mouse is returned for easy evaluation,
+        * to get the real version number the decimal point has to be shifted 2
+        * positions to the left. E.g. a value of 138 means 1.38.
+        */
+       __ATTR(firmware_version, 0440,
+                       kone_sysfs_show_firmware_version, NULL),
 
-static struct bin_attribute kone_profile3_attr = {
-       .attr = { .name = "profile3", .mode = 0660 },
-       .size = sizeof(struct kone_profile),
-       .read = kone_sysfs_read_profile3,
-       .write = kone_sysfs_write_profile3
-};
+       /*
+        * Prints state of Tracking Control Unit as number where 0 = off and
+        * 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and
+        * activates the tcu
+        */
+       __ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu),
 
-static struct bin_attribute kone_profile4_attr = {
-       .attr = { .name = "profile4", .mode = 0660 },
-       .size = sizeof(struct kone_profile),
-       .read = kone_sysfs_read_profile4,
-       .write = kone_sysfs_write_profile4
+       /* Prints and takes the number of the profile the mouse starts with */
+       __ATTR(startup_profile, 0660,
+                       kone_sysfs_show_startup_profile,
+                       kone_sysfs_set_startup_profile),
+       __ATTR_NULL
 };
 
-static struct bin_attribute kone_profile5_attr = {
-       .attr = { .name = "profile5", .mode = 0660 },
-       .size = sizeof(struct kone_profile),
-       .read = kone_sysfs_read_profile5,
-       .write = kone_sysfs_write_profile5
+static struct bin_attribute kone_bin_attributes[] = {
+       {
+               .attr = { .name = "settings", .mode = 0660 },
+               .size = sizeof(struct kone_settings),
+               .read = kone_sysfs_read_settings,
+               .write = kone_sysfs_write_settings
+       },
+       {
+               .attr = { .name = "profile1", .mode = 0660 },
+               .size = sizeof(struct kone_profile),
+               .read = kone_sysfs_read_profilex,
+               .write = kone_sysfs_write_profilex,
+               .private = &profile_numbers[0]
+       },
+       {
+               .attr = { .name = "profile2", .mode = 0660 },
+               .size = sizeof(struct kone_profile),
+               .read = kone_sysfs_read_profilex,
+               .write = kone_sysfs_write_profilex,
+               .private = &profile_numbers[1]
+       },
+       {
+               .attr = { .name = "profile3", .mode = 0660 },
+               .size = sizeof(struct kone_profile),
+               .read = kone_sysfs_read_profilex,
+               .write = kone_sysfs_write_profilex,
+               .private = &profile_numbers[2]
+       },
+       {
+               .attr = { .name = "profile4", .mode = 0660 },
+               .size = sizeof(struct kone_profile),
+               .read = kone_sysfs_read_profilex,
+               .write = kone_sysfs_write_profilex,
+               .private = &profile_numbers[3]
+       },
+       {
+               .attr = { .name = "profile5", .mode = 0660 },
+               .size = sizeof(struct kone_profile),
+               .read = kone_sysfs_read_profilex,
+               .write = kone_sysfs_write_profilex,
+               .private = &profile_numbers[4]
+       },
+       __ATTR_NULL
 };
 
-static int kone_create_sysfs_attributes(struct usb_interface *intf)
-{
-       int retval;
-
-       retval = sysfs_create_group(&intf->dev.kobj, &kone_attribute_group);
-       if (retval)
-               goto exit_1;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_settings_attr);
-       if (retval)
-               goto exit_2;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile1_attr);
-       if (retval)
-               goto exit_3;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile2_attr);
-       if (retval)
-               goto exit_4;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile3_attr);
-       if (retval)
-               goto exit_5;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile4_attr);
-       if (retval)
-               goto exit_6;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile5_attr);
-       if (retval)
-               goto exit_7;
-
-       return 0;
-
-exit_7:
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr);
-exit_6:
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr);
-exit_5:
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr);
-exit_4:
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr);
-exit_3:
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr);
-exit_2:
-       sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group);
-exit_1:
-       return retval;
-}
-
-static void kone_remove_sysfs_attributes(struct usb_interface *intf)
-{
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile5_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr);
-       sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group);
-}
-
 static int kone_init_kone_device_struct(struct usb_device *usb_dev,
                struct kone_device *kone)
 {
@@ -818,32 +716,25 @@ static int kone_init_specials(struct hid_device *hdev)
 
                kone = kzalloc(sizeof(*kone), GFP_KERNEL);
                if (!kone) {
-                       dev_err(&hdev->dev, "can't alloc device descriptor\n");
+                       hid_err(hdev, "can't alloc device descriptor\n");
                        return -ENOMEM;
                }
                hid_set_drvdata(hdev, kone);
 
                retval = kone_init_kone_device_struct(usb_dev, kone);
                if (retval) {
-                       dev_err(&hdev->dev,
-                                       "couldn't init struct kone_device\n");
+                       hid_err(hdev, "couldn't init struct kone_device\n");
                        goto exit_free;
                }
 
-               retval = roccat_connect(hdev);
+               retval = roccat_connect(kone_class, hdev);
                if (retval < 0) {
-                       dev_err(&hdev->dev, "couldn't init char dev\n");
+                       hid_err(hdev, "couldn't init char dev\n");
                        /* be tolerant about not getting chrdev */
                } else {
                        kone->roccat_claimed = 1;
                        kone->chrdev_minor = retval;
                }
-
-               retval = kone_create_sysfs_attributes(intf);
-               if (retval) {
-                       dev_err(&hdev->dev, "cannot create sysfs files\n");
-                       goto exit_free;
-               }
        } else {
                hid_set_drvdata(hdev, NULL);
        }
@@ -854,7 +745,6 @@ exit_free:
        return retval;
 }
 
-
 static void kone_remove_specials(struct hid_device *hdev)
 {
        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
@@ -862,7 +752,6 @@ static void kone_remove_specials(struct hid_device *hdev)
 
        if (intf->cur_altsetting->desc.bInterfaceProtocol
                        == USB_INTERFACE_PROTOCOL_MOUSE) {
-               kone_remove_sysfs_attributes(intf);
                kone = hid_get_drvdata(hdev);
                if (kone->roccat_claimed)
                        roccat_disconnect(kone->chrdev_minor);
@@ -876,19 +765,19 @@ static int kone_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        retval = hid_parse(hdev);
        if (retval) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto exit;
        }
 
        retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (retval) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto exit;
        }
 
        retval = kone_init_specials(hdev);
        if (retval) {
-               dev_err(&hdev->dev, "couldn't install mouse\n");
+               hid_err(hdev, "couldn't install mouse\n");
                goto exit_stop;
        }
 
@@ -1006,11 +895,24 @@ static struct hid_driver kone_driver = {
 
 static int __init kone_init(void)
 {
-       return hid_register_driver(&kone_driver);
+       int retval;
+
+       /* class name has to be same as driver name */
+       kone_class = class_create(THIS_MODULE, "kone");
+       if (IS_ERR(kone_class))
+               return PTR_ERR(kone_class);
+       kone_class->dev_attrs = kone_attributes;
+       kone_class->dev_bin_attrs = kone_bin_attributes;
+
+       retval = hid_register_driver(&kone_driver);
+       if (retval)
+               class_destroy(kone_class);
+       return retval;
 }
 
 static void __exit kone_exit(void)
 {
+       class_destroy(kone_class);
        hid_unregister_driver(&kone_driver);
 }
 
index 130d6566ea8269e1c51a0bd604fda7378e315474..64abb5b8a59a5909a759f3ef37e232a8991fb902 100644 (file)
 
 #include <linux/types.h>
 
-#pragma pack(push)
-#pragma pack(1)
-
 struct kone_keystroke {
        uint8_t key;
        uint8_t action;
        uint16_t period; /* in milliseconds */
-};
+} __attribute__ ((__packed__));
 
 enum kone_keystroke_buttons {
        kone_keystroke_button_1 = 0xf0, /* left mouse button */
@@ -44,7 +41,7 @@ struct kone_button_info {
        uint8_t macro_name[16]; /* can be max 15 chars long */
        uint8_t count;
        struct kone_keystroke keystrokes[20];
-};
+} __attribute__ ((__packed__));
 
 enum kone_button_info_types {
        /* valid button types until firmware 1.32 */
@@ -95,7 +92,7 @@ struct kone_light_info {
        uint8_t red;   /* range 0x00-0xff */
        uint8_t green; /* range 0x00-0xff */
        uint8_t blue;  /* range 0x00-0xff */
-};
+} __attribute__ ((__packed__));
 
 struct kone_profile {
        uint16_t size; /* always 975 */
@@ -130,7 +127,7 @@ struct kone_profile {
        struct kone_button_info button_infos[8];
 
        uint16_t checksum; /* \brief holds checksum of struct */
-};
+} __attribute__ ((__packed__));
 
 enum kone_polling_rates {
        kone_polling_rate_125 = 1,
@@ -147,7 +144,7 @@ struct kone_settings {
        uint8_t  calibration_data[4];
        uint8_t  unknown3[2];
        uint16_t checksum;
-};
+} __attribute__ ((__packed__));
 
 /*
  * 12 byte mouse event read by interrupt_read
@@ -163,7 +160,7 @@ struct kone_mouse_event {
        uint8_t event;
        uint8_t value; /* press = 0, release = 1 */
        uint8_t macro_key; /* 0 to 8 */
-};
+} __attribute__ ((__packed__));
 
 enum kone_mouse_events {
        /* osd events are thought to be display on screen */
@@ -191,9 +188,7 @@ struct kone_roccat_report {
        uint8_t event;
        uint8_t value; /* holds dpi or profile value */
        uint8_t key; /* macro key on overlong macro execution */
-};
-
-#pragma pack(pop)
+} __attribute__ ((__packed__));
 
 struct kone_device {
        /*
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
new file mode 100644 (file)
index 0000000..1608c8d
--- /dev/null
@@ -0,0 +1,837 @@
+/*
+ * Roccat Kone[+] driver for Linux
+ *
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.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.
+ */
+
+/*
+ * Roccat Kone[+] is an updated/improved version of the Kone with more memory
+ * and functionality and without the non-standard behaviours the Kone had.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "hid-ids.h"
+#include "hid-roccat.h"
+#include "hid-roccat-koneplus.h"
+
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+static struct class *koneplus_class;
+
+static void koneplus_profile_activated(struct koneplus_device *koneplus,
+               uint new_profile)
+{
+       koneplus->actual_profile = new_profile;
+}
+
+static int koneplus_send_control(struct usb_device *usb_dev, uint value,
+               enum koneplus_control_requests request)
+{
+       int len;
+       struct koneplus_control *control;
+
+       if ((request == KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
+                       request == KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
+                       value > 4)
+               return -EINVAL;
+
+       control = kmalloc(sizeof(struct koneplus_control), GFP_KERNEL);
+       if (!control)
+               return -ENOMEM;
+
+       control->command = KONEPLUS_COMMAND_CONTROL;
+       control->value = value;
+       control->request = request;
+
+       len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                       USB_REQ_SET_CONFIGURATION,
+                       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                       KONEPLUS_USB_COMMAND_CONTROL, 0, control,
+                       sizeof(struct koneplus_control),
+                       USB_CTRL_SET_TIMEOUT);
+
+       kfree(control);
+
+       if (len != sizeof(struct koneplus_control))
+               return len;
+
+       return 0;
+}
+
+static int koneplus_receive(struct usb_device *usb_dev, uint usb_command,
+               void *buf, uint size) {
+       int len;
+
+       len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+                       USB_REQ_CLEAR_FEATURE,
+                       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                       usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+
+       return (len != size) ? -EIO : 0;
+}
+
+static int koneplus_receive_control_status(struct usb_device *usb_dev)
+{
+       int retval;
+       struct koneplus_control *control;
+
+       control = kmalloc(sizeof(struct koneplus_control), GFP_KERNEL);
+       if (!control)
+               return -ENOMEM;
+
+       do {
+               retval = koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_CONTROL,
+                               control, sizeof(struct koneplus_control));
+
+               /* check if we get a completely wrong answer */
+               if (retval)
+                       goto out;
+
+               if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_OK) {
+                       retval = 0;
+                       goto out;
+               }
+
+               /* indicates that hardware needs some more time to complete action */
+               if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_WAIT) {
+                       msleep(500); /* windows driver uses 1000 */
+                       continue;
+               }
+
+               /* seems to be critical - replug necessary */
+               if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD) {
+                       retval = -EINVAL;
+                       goto out;
+               }
+
+               dev_err(&usb_dev->dev, "koneplus_receive_control_status: "
+                               "unknown response value 0x%x\n", control->value);
+               retval = -EINVAL;
+               goto out;
+
+       } while (1);
+out:
+       kfree(control);
+       return retval;
+}
+
+static int koneplus_send(struct usb_device *usb_dev, uint command,
+               void *buf, uint size) {
+       int len;
+
+       len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                       USB_REQ_SET_CONFIGURATION,
+                       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                       command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+
+       if (len != size)
+               return -EIO;
+
+       if (koneplus_receive_control_status(usb_dev))
+               return -EIO;
+
+       return 0;
+}
+
+static int koneplus_select_profile(struct usb_device *usb_dev, uint number,
+               enum koneplus_control_requests request)
+{
+       int retval;
+
+       retval = koneplus_send_control(usb_dev, number, request);
+       if (retval)
+               return retval;
+
+       /* allow time to settle things - windows driver uses 500 */
+       msleep(100);
+
+       retval = koneplus_receive_control_status(usb_dev);
+       if (retval)
+               return retval;
+
+       return 0;
+}
+
+static int koneplus_get_info(struct usb_device *usb_dev,
+               struct koneplus_info *buf)
+{
+       return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_INFO,
+                       buf, sizeof(struct koneplus_info));
+}
+
+static int koneplus_get_profile_settings(struct usb_device *usb_dev,
+               struct koneplus_profile_settings *buf, uint number)
+{
+       int retval;
+
+       retval = koneplus_select_profile(usb_dev, number,
+                       KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
+       if (retval)
+               return retval;
+
+       return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
+                       buf, sizeof(struct koneplus_profile_settings));
+}
+
+static int koneplus_set_profile_settings(struct usb_device *usb_dev,
+               struct koneplus_profile_settings const *settings)
+{
+       return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
+                       (void *)settings, sizeof(struct koneplus_profile_settings));
+}
+
+static int koneplus_get_profile_buttons(struct usb_device *usb_dev,
+               struct koneplus_profile_buttons *buf, int number)
+{
+       int retval;
+
+       retval = koneplus_select_profile(usb_dev, number,
+                       KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
+       if (retval)
+               return retval;
+
+       return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
+                       buf, sizeof(struct koneplus_profile_buttons));
+}
+
+static int koneplus_set_profile_buttons(struct usb_device *usb_dev,
+               struct koneplus_profile_buttons const *buttons)
+{
+       return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
+                       (void *)buttons, sizeof(struct koneplus_profile_buttons));
+}
+
+/* retval is 0-4 on success, < 0 on error */
+static int koneplus_get_startup_profile(struct usb_device *usb_dev)
+{
+       struct koneplus_startup_profile *buf;
+       int retval;
+
+       buf = kmalloc(sizeof(struct koneplus_startup_profile), GFP_KERNEL);
+
+       retval = koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
+                       buf, sizeof(struct koneplus_startup_profile));
+
+       if (retval)
+               goto out;
+
+       retval = buf->startup_profile;
+out:
+       kfree(buf);
+       return retval;
+}
+
+static int koneplus_set_startup_profile(struct usb_device *usb_dev,
+               int startup_profile)
+{
+       struct koneplus_startup_profile buf;
+
+       buf.command = KONEPLUS_COMMAND_STARTUP_PROFILE;
+       buf.size = sizeof(struct koneplus_startup_profile);
+       buf.startup_profile = startup_profile;
+
+       return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
+                       (char *)&buf, sizeof(struct koneplus_profile_buttons));
+}
+
+static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
+               char *buf, loff_t off, size_t count,
+               size_t real_size, uint command)
+{
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+       struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+       int retval;
+
+       if (off != 0 || count != real_size)
+               return -EINVAL;
+
+       mutex_lock(&koneplus->koneplus_lock);
+       retval = koneplus_receive(usb_dev, command, buf, real_size);
+       mutex_unlock(&koneplus->koneplus_lock);
+
+       if (retval)
+               return retval;
+
+       return real_size;
+}
+
+static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
+               void const *buf, loff_t off, size_t count,
+               size_t real_size, uint command)
+{
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+       struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+       int retval;
+
+       if (off != 0 || count != real_size)
+               return -EINVAL;
+
+       mutex_lock(&koneplus->koneplus_lock);
+       retval = koneplus_send(usb_dev, command, (void *)buf, real_size);
+       mutex_unlock(&koneplus->koneplus_lock);
+
+       if (retval)
+               return retval;
+
+       return real_size;
+}
+
+static ssize_t koneplus_sysfs_write_macro(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr, char *buf,
+               loff_t off, size_t count)
+{
+       return koneplus_sysfs_write(fp, kobj, buf, off, count,
+                       sizeof(struct koneplus_macro), KONEPLUS_USB_COMMAND_MACRO);
+}
+
+static ssize_t koneplus_sysfs_read_sensor(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr, char *buf,
+               loff_t off, size_t count)
+{
+       return koneplus_sysfs_read(fp, kobj, buf, off, count,
+                       sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR);
+}
+
+static ssize_t koneplus_sysfs_write_sensor(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr, char *buf,
+               loff_t off, size_t count)
+{
+       return koneplus_sysfs_write(fp, kobj, buf, off, count,
+                       sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR);
+}
+
+static ssize_t koneplus_sysfs_write_tcu(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr, char *buf,
+               loff_t off, size_t count)
+{
+       return koneplus_sysfs_write(fp, kobj, buf, off, count,
+                       sizeof(struct koneplus_tcu), KONEPLUS_USB_COMMAND_TCU);
+}
+
+static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr, char *buf,
+               loff_t off, size_t count)
+{
+       return koneplus_sysfs_read(fp, kobj, buf, off, count,
+                       sizeof(struct koneplus_tcu_image), KONEPLUS_USB_COMMAND_TCU);
+}
+
+static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr, char *buf,
+               loff_t off, size_t count)
+{
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+
+       if (off >= sizeof(struct koneplus_profile_settings))
+               return 0;
+
+       if (off + count > sizeof(struct koneplus_profile_settings))
+               count = sizeof(struct koneplus_profile_settings) - off;
+
+       mutex_lock(&koneplus->koneplus_lock);
+       memcpy(buf, ((void const *)&koneplus->profile_settings[*(uint *)(attr->private)]) + off,
+                       count);
+       mutex_unlock(&koneplus->koneplus_lock);
+
+       return count;
+}
+
+static ssize_t koneplus_sysfs_write_profile_settings(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr, char *buf,
+               loff_t off, size_t count)
+{
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+       struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+       int retval = 0;
+       int difference;
+       int profile_number;
+       struct koneplus_profile_settings *profile_settings;
+
+       if (off != 0 || count != sizeof(struct koneplus_profile_settings))
+               return -EINVAL;
+
+       profile_number = ((struct koneplus_profile_settings const *)buf)->number;
+       profile_settings = &koneplus->profile_settings[profile_number];
+
+       mutex_lock(&koneplus->koneplus_lock);
+       difference = memcmp(buf, profile_settings,
+                       sizeof(struct koneplus_profile_settings));
+       if (difference) {
+               retval = koneplus_set_profile_settings(usb_dev,
+                               (struct koneplus_profile_settings const *)buf);
+               if (!retval)
+                       memcpy(profile_settings, buf,
+                                       sizeof(struct koneplus_profile_settings));
+       }
+       mutex_unlock(&koneplus->koneplus_lock);
+
+       if (retval)
+               return retval;
+
+       return sizeof(struct koneplus_profile_settings);
+}
+
+static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr, char *buf,
+               loff_t off, size_t count)
+{
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+
+       if (off >= sizeof(struct koneplus_profile_buttons))
+               return 0;
+
+       if (off + count > sizeof(struct koneplus_profile_buttons))
+               count = sizeof(struct koneplus_profile_buttons) - off;
+
+       mutex_lock(&koneplus->koneplus_lock);
+       memcpy(buf, ((void const *)&koneplus->profile_buttons[*(uint *)(attr->private)]) + off,
+                       count);
+       mutex_unlock(&koneplus->koneplus_lock);
+
+       return count;
+}
+
+static ssize_t koneplus_sysfs_write_profile_buttons(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr, char *buf,
+               loff_t off, size_t count)
+{
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+       struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+       int retval = 0;
+       int difference;
+       uint profile_number;
+       struct koneplus_profile_buttons *profile_buttons;
+
+       if (off != 0 || count != sizeof(struct koneplus_profile_buttons))
+               return -EINVAL;
+
+       profile_number = ((struct koneplus_profile_buttons const *)buf)->number;
+       profile_buttons = &koneplus->profile_buttons[profile_number];
+
+       mutex_lock(&koneplus->koneplus_lock);
+       difference = memcmp(buf, profile_buttons,
+                       sizeof(struct koneplus_profile_buttons));
+       if (difference) {
+               retval = koneplus_set_profile_buttons(usb_dev,
+                               (struct koneplus_profile_buttons const *)buf);
+               if (!retval)
+                       memcpy(profile_buttons, buf,
+                                       sizeof(struct koneplus_profile_buttons));
+       }
+       mutex_unlock(&koneplus->koneplus_lock);
+
+       if (retval)
+               return retval;
+
+       return sizeof(struct koneplus_profile_buttons);
+}
+
+static ssize_t koneplus_sysfs_show_startup_profile(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct koneplus_device *koneplus =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+       return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->startup_profile);
+}
+
+static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev,
+               struct device_attribute *attr, char const *buf, size_t size)
+{
+       struct koneplus_device *koneplus;
+       struct usb_device *usb_dev;
+       unsigned long profile;
+       int retval;
+
+       dev = dev->parent->parent;
+       koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+       usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
+       retval = strict_strtoul(buf, 10, &profile);
+       if (retval)
+               return retval;
+
+       mutex_lock(&koneplus->koneplus_lock);
+       retval = koneplus_set_startup_profile(usb_dev, profile);
+       mutex_unlock(&koneplus->koneplus_lock);
+       if (retval)
+               return retval;
+
+       return size;
+}
+
+static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct koneplus_device *koneplus =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+       return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
+}
+
+static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct koneplus_device *koneplus =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+       return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->info.firmware_version);
+}
+
+static struct device_attribute koneplus_attributes[] = {
+       __ATTR(startup_profile, 0660,
+                       koneplus_sysfs_show_startup_profile,
+                       koneplus_sysfs_set_startup_profile),
+       __ATTR(actual_profile, 0440,
+                       koneplus_sysfs_show_actual_profile, NULL),
+       __ATTR(firmware_version, 0440,
+                       koneplus_sysfs_show_firmware_version, NULL),
+       __ATTR_NULL
+};
+
+static struct bin_attribute koneplus_bin_attributes[] = {
+       {
+               .attr = { .name = "sensor", .mode = 0220 },
+               .size = sizeof(struct koneplus_sensor),
+               .read = koneplus_sysfs_read_sensor,
+               .write = koneplus_sysfs_write_sensor
+       },
+       {
+               .attr = { .name = "tcu", .mode = 0220 },
+               .size = sizeof(struct koneplus_tcu),
+               .write = koneplus_sysfs_write_tcu
+       },
+       {
+               .attr = { .name = "tcu_image", .mode = 0440 },
+               .size = sizeof(struct koneplus_tcu_image),
+               .read = koneplus_sysfs_read_tcu_image
+       },
+       {
+               .attr = { .name = "profile_settings", .mode = 0220 },
+               .size = sizeof(struct koneplus_profile_settings),
+               .write = koneplus_sysfs_write_profile_settings
+       },
+       {
+               .attr = { .name = "profile1_settings", .mode = 0440 },
+               .size = sizeof(struct koneplus_profile_settings),
+               .read = koneplus_sysfs_read_profilex_settings,
+               .private = &profile_numbers[0]
+       },
+       {
+               .attr = { .name = "profile2_settings", .mode = 0440 },
+               .size = sizeof(struct koneplus_profile_settings),
+               .read = koneplus_sysfs_read_profilex_settings,
+               .private = &profile_numbers[1]
+       },
+       {
+               .attr = { .name = "profile3_settings", .mode = 0440 },
+               .size = sizeof(struct koneplus_profile_settings),
+               .read = koneplus_sysfs_read_profilex_settings,
+               .private = &profile_numbers[2]
+       },
+       {
+               .attr = { .name = "profile4_settings", .mode = 0440 },
+               .size = sizeof(struct koneplus_profile_settings),
+               .read = koneplus_sysfs_read_profilex_settings,
+               .private = &profile_numbers[3]
+       },
+       {
+               .attr = { .name = "profile5_settings", .mode = 0440 },
+               .size = sizeof(struct koneplus_profile_settings),
+               .read = koneplus_sysfs_read_profilex_settings,
+               .private = &profile_numbers[4]
+       },
+       {
+               .attr = { .name = "profile_buttons", .mode = 0220 },
+               .size = sizeof(struct koneplus_profile_buttons),
+               .write = koneplus_sysfs_write_profile_buttons
+       },
+       {
+               .attr = { .name = "profile1_buttons", .mode = 0440 },
+               .size = sizeof(struct koneplus_profile_buttons),
+               .read = koneplus_sysfs_read_profilex_buttons,
+               .private = &profile_numbers[0]
+       },
+       {
+               .attr = { .name = "profile2_buttons", .mode = 0440 },
+               .size = sizeof(struct koneplus_profile_buttons),
+               .read = koneplus_sysfs_read_profilex_buttons,
+               .private = &profile_numbers[1]
+       },
+       {
+               .attr = { .name = "profile3_buttons", .mode = 0440 },
+               .size = sizeof(struct koneplus_profile_buttons),
+               .read = koneplus_sysfs_read_profilex_buttons,
+               .private = &profile_numbers[2]
+       },
+       {
+               .attr = { .name = "profile4_buttons", .mode = 0440 },
+               .size = sizeof(struct koneplus_profile_buttons),
+               .read = koneplus_sysfs_read_profilex_buttons,
+               .private = &profile_numbers[3]
+       },
+       {
+               .attr = { .name = "profile5_buttons", .mode = 0440 },
+               .size = sizeof(struct koneplus_profile_buttons),
+               .read = koneplus_sysfs_read_profilex_buttons,
+               .private = &profile_numbers[4]
+       },
+       {
+               .attr = { .name = "macro", .mode = 0220 },
+               .size = sizeof(struct koneplus_macro),
+               .write = koneplus_sysfs_write_macro
+       },
+       __ATTR_NULL
+};
+
+static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
+               struct koneplus_device *koneplus)
+{
+       int retval, i;
+       static uint wait = 70; /* device will freeze with just 60 */
+
+       mutex_init(&koneplus->koneplus_lock);
+
+       koneplus->startup_profile = koneplus_get_startup_profile(usb_dev);
+
+       msleep(wait);
+       retval = koneplus_get_info(usb_dev, &koneplus->info);
+       if (retval)
+               return retval;
+
+       for (i = 0; i < 5; ++i) {
+               msleep(wait);
+               retval = koneplus_get_profile_settings(usb_dev,
+                               &koneplus->profile_settings[i], i);
+               if (retval)
+                       return retval;
+
+               msleep(wait);
+               retval = koneplus_get_profile_buttons(usb_dev,
+                               &koneplus->profile_buttons[i], i);
+               if (retval)
+                       return retval;
+       }
+
+       koneplus_profile_activated(koneplus, koneplus->startup_profile);
+
+       return 0;
+}
+
+static int koneplus_init_specials(struct hid_device *hdev)
+{
+       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       struct koneplus_device *koneplus;
+       int retval;
+
+       if (intf->cur_altsetting->desc.bInterfaceProtocol
+                       == USB_INTERFACE_PROTOCOL_MOUSE) {
+
+               koneplus = kzalloc(sizeof(*koneplus), GFP_KERNEL);
+               if (!koneplus) {
+                       dev_err(&hdev->dev, "can't alloc device descriptor\n");
+                       return -ENOMEM;
+               }
+               hid_set_drvdata(hdev, koneplus);
+
+               retval = koneplus_init_koneplus_device_struct(usb_dev, koneplus);
+               if (retval) {
+                       dev_err(&hdev->dev,
+                                       "couldn't init struct koneplus_device\n");
+                       goto exit_free;
+               }
+
+               retval = roccat_connect(koneplus_class, hdev);
+               if (retval < 0) {
+                       dev_err(&hdev->dev, "couldn't init char dev\n");
+               } else {
+                       koneplus->chrdev_minor = retval;
+                       koneplus->roccat_claimed = 1;
+               }
+       } else {
+               hid_set_drvdata(hdev, NULL);
+       }
+
+       return 0;
+exit_free:
+       kfree(koneplus);
+       return retval;
+}
+
+static void koneplus_remove_specials(struct hid_device *hdev)
+{
+       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+       struct koneplus_device *koneplus;
+
+       if (intf->cur_altsetting->desc.bInterfaceProtocol
+                       == USB_INTERFACE_PROTOCOL_MOUSE) {
+               koneplus = hid_get_drvdata(hdev);
+               if (koneplus->roccat_claimed)
+                       roccat_disconnect(koneplus->chrdev_minor);
+               kfree(koneplus);
+       }
+}
+
+static int koneplus_probe(struct hid_device *hdev,
+               const struct hid_device_id *id)
+{
+       int retval;
+
+       retval = hid_parse(hdev);
+       if (retval) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto exit;
+       }
+
+       retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (retval) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto exit;
+       }
+
+       retval = koneplus_init_specials(hdev);
+       if (retval) {
+               dev_err(&hdev->dev, "couldn't install mouse\n");
+               goto exit_stop;
+       }
+
+       return 0;
+
+exit_stop:
+       hid_hw_stop(hdev);
+exit:
+       return retval;
+}
+
+static void koneplus_remove(struct hid_device *hdev)
+{
+       koneplus_remove_specials(hdev);
+       hid_hw_stop(hdev);
+}
+
+static void koneplus_keep_values_up_to_date(struct koneplus_device *koneplus,
+               u8 const *data)
+{
+       struct koneplus_mouse_report_button const *button_report;
+
+       switch (data[0]) {
+       case KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON:
+               button_report = (struct koneplus_mouse_report_button const *)data;
+               switch (button_report->type) {
+               case KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE:
+                       koneplus_profile_activated(koneplus, button_report->data1 - 1);
+                       break;
+               }
+               break;
+       }
+}
+
+static void koneplus_report_to_chrdev(struct koneplus_device const *koneplus,
+               u8 const *data)
+{
+       struct koneplus_roccat_report roccat_report;
+       struct koneplus_mouse_report_button const *button_report;
+
+       if (data[0] != KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON)
+               return;
+
+       button_report = (struct koneplus_mouse_report_button const *)data;
+
+       if ((button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
+                       button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) &&
+                       button_report->data2 != KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS)
+               return;
+
+       roccat_report.type = button_report->type;
+       roccat_report.data1 = button_report->data1;
+       roccat_report.data2 = button_report->data2;
+       roccat_report.profile = koneplus->actual_profile + 1;
+       roccat_report_event(koneplus->chrdev_minor,
+                       (uint8_t const *)&roccat_report,
+                       sizeof(struct koneplus_roccat_report));
+}
+
+static int koneplus_raw_event(struct hid_device *hdev,
+               struct hid_report *report, u8 *data, int size)
+{
+       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+       struct koneplus_device *koneplus = hid_get_drvdata(hdev);
+
+       if (intf->cur_altsetting->desc.bInterfaceProtocol
+                       != USB_INTERFACE_PROTOCOL_MOUSE)
+               return 0;
+
+       koneplus_keep_values_up_to_date(koneplus, data);
+
+       if (koneplus->roccat_claimed)
+               koneplus_report_to_chrdev(koneplus, data);
+
+       return 0;
+}
+
+static const struct hid_device_id koneplus_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
+       { }
+};
+
+MODULE_DEVICE_TABLE(hid, koneplus_devices);
+
+static struct hid_driver koneplus_driver = {
+               .name = "koneplus",
+               .id_table = koneplus_devices,
+               .probe = koneplus_probe,
+               .remove = koneplus_remove,
+               .raw_event = koneplus_raw_event
+};
+
+static int __init koneplus_init(void)
+{
+       int retval;
+
+       /* class name has to be same as driver name */
+       koneplus_class = class_create(THIS_MODULE, "koneplus");
+       if (IS_ERR(koneplus_class))
+               return PTR_ERR(koneplus_class);
+       koneplus_class->dev_attrs = koneplus_attributes;
+       koneplus_class->dev_bin_attrs = koneplus_bin_attributes;
+
+       retval = hid_register_driver(&koneplus_driver);
+       if (retval)
+               class_destroy(koneplus_class);
+       return retval;
+}
+
+static void __exit koneplus_exit(void)
+{
+       class_destroy(koneplus_class);
+       hid_unregister_driver(&koneplus_driver);
+}
+
+module_init(koneplus_init);
+module_exit(koneplus_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat Kone[+] driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h
new file mode 100644 (file)
index 0000000..57a5c1a
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef __HID_ROCCAT_KONEPLUS_H
+#define __HID_ROCCAT_KONEPLUS_H
+
+/*
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.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/types.h>
+
+/*
+ * case 1: writes request 80 and reads value 1
+ *
+ */
+struct koneplus_control {
+       uint8_t command; /* KONEPLUS_COMMAND_CONTROL */
+       /*
+        * value is profile number in range 0-4 for requesting settings and buttons
+        * 1 if status ok for requesting status
+        */
+       uint8_t value;
+       uint8_t request;
+} __attribute__ ((__packed__));
+
+enum koneplus_control_requests {
+       KONEPLUS_CONTROL_REQUEST_STATUS = 0x00,
+       KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x80,
+       KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x90,
+};
+
+enum koneplus_control_values {
+       KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD = 0,
+       KONEPLUS_CONTROL_REQUEST_STATUS_OK = 1,
+       KONEPLUS_CONTROL_REQUEST_STATUS_WAIT = 3,
+};
+
+struct koneplus_startup_profile {
+       uint8_t command; /* KONEPLUS_COMMAND_STARTUP_PROFILE */
+       uint8_t size; /* always 3 */
+       uint8_t startup_profile; /* Range 0-4! */
+} __attribute__ ((__packed__));
+
+struct koneplus_profile_settings {
+       uint8_t command; /* KONEPLUS_COMMAND_PROFILE_SETTINGS */
+       uint8_t size; /* always 43 */
+       uint8_t number; /* range 0-4 */
+       uint8_t advanced_sensitivity;
+       uint8_t sensitivity_x;
+       uint8_t sensitivity_y;
+       uint8_t cpi_levels_enabled;
+       uint8_t cpi_levels_x[5];
+       uint8_t cpi_startup_level; /* range 0-4 */
+       uint8_t cpi_levels_y[5]; /* range 1-60 means 100-6000 cpi */
+       uint8_t unknown1;
+       uint8_t polling_rate;
+       uint8_t lights_enabled;
+       uint8_t light_effect_mode;
+       uint8_t color_flow_effect;
+       uint8_t light_effect_type;
+       uint8_t light_effect_speed;
+       uint8_t lights[16];
+       uint16_t checksum;
+} __attribute__ ((__packed__));
+
+struct koneplus_profile_buttons {
+       uint8_t command; /* KONEPLUS_COMMAND_PROFILE_BUTTONS */
+       uint8_t size; /* always 77 */
+       uint8_t number; /* range 0-4 */
+       uint8_t data[72];
+       uint16_t checksum;
+} __attribute__ ((__packed__));
+
+struct koneplus_macro {
+       uint8_t command; /* KONEPLUS_COMMAND_MACRO */
+       uint16_t size; /* always 0x822 little endian */
+       uint8_t profile; /* range 0-4 */
+       uint8_t button; /* range 0-23 */
+       uint8_t data[2075];
+       uint16_t checksum;
+} __attribute__ ((__packed__));
+
+struct koneplus_info {
+       uint8_t command; /* KONEPLUS_COMMAND_INFO */
+       uint8_t size; /* always 6 */
+       uint8_t firmware_version;
+       uint8_t unknown[3];
+} __attribute__ ((__packed__));
+
+struct koneplus_e {
+       uint8_t command; /* KONEPLUS_COMMAND_E */
+       uint8_t size; /* always 3 */
+       uint8_t unknown; /* TODO 1; 0 before firmware update */
+} __attribute__ ((__packed__));
+
+struct koneplus_sensor {
+       uint8_t command;  /* KONEPLUS_COMMAND_SENSOR */
+       uint8_t size; /* always 6 */
+       uint8_t data[4];
+} __attribute__ ((__packed__));
+
+struct koneplus_firmware_write {
+       uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE */
+       uint8_t unknown[1025];
+} __attribute__ ((__packed__));
+
+struct koneplus_firmware_write_control {
+       uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL */
+       /*
+        * value is 1 on success
+        * 3 means "not finished yet"
+        */
+       uint8_t value;
+       uint8_t unknown; /* always 0x75 */
+} __attribute__ ((__packed__));
+
+struct koneplus_tcu {
+       uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */
+       uint8_t data[2];
+} __attribute__ ((__packed__));
+
+struct koneplus_tcu_image {
+       uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */
+       uint8_t data[1024];
+       uint16_t checksum;
+} __attribute__ ((__packed__));
+
+enum koneplus_commands {
+       KONEPLUS_COMMAND_CONTROL = 0x4,
+       KONEPLUS_COMMAND_STARTUP_PROFILE = 0x5,
+       KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
+       KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
+       KONEPLUS_COMMAND_MACRO = 0x8,
+       KONEPLUS_COMMAND_INFO = 0x9,
+       KONEPLUS_COMMAND_E = 0xe,
+       KONEPLUS_COMMAND_SENSOR = 0xf,
+       KONEPLUS_COMMAND_FIRMWARE_WRITE = 0x1b,
+       KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
+};
+
+enum koneplus_usb_commands {
+       KONEPLUS_USB_COMMAND_CONTROL = 0x304,
+       KONEPLUS_USB_COMMAND_STARTUP_PROFILE = 0x305,
+       KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
+       KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
+       KONEPLUS_USB_COMMAND_MACRO = 0x308,
+       KONEPLUS_USB_COMMAND_INFO = 0x309,
+       KONEPLUS_USB_COMMAND_TCU = 0x30c,
+       KONEPLUS_USB_COMMAND_E = 0x30e,
+       KONEPLUS_USB_COMMAND_SENSOR = 0x30f,
+       KONEPLUS_USB_COMMAND_FIRMWARE_WRITE = 0x31b,
+       KONEPLUS_USB_COMMAND_FIRMWARE_WRITE_CONTROL = 0x31c,
+};
+
+enum koneplus_mouse_report_numbers {
+       KONEPLUS_MOUSE_REPORT_NUMBER_HID = 1,
+       KONEPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2,
+       KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON = 3,
+};
+
+struct koneplus_mouse_report_button {
+       uint8_t report_number; /* always KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON */
+       uint8_t zero1;
+       uint8_t type;
+       uint8_t data1;
+       uint8_t data2;
+       uint8_t zero2;
+       uint8_t unknown[2];
+} __attribute__ ((__packed__));
+
+enum koneplus_mouse_report_button_types {
+       /* data1 = new profile range 1-5 */
+       KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE = 0x20,
+
+       /* data1 = button number range 1-24; data2 = action */
+       KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH = 0x60,
+
+       /* data1 = button number range 1-24; data2 = action */
+       KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER = 0x80,
+
+       /* data1 = setting number range 1-5 */
+       KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI = 0xb0,
+
+       /* data1 and data2 = range 0x1-0xb */
+       KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY = 0xc0,
+
+       /* data1 = 22 = next track...
+        * data2 = action
+        */
+       KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
+};
+
+enum koneplus_mouse_report_button_action {
+       KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS = 0,
+       KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_RELEASE = 1,
+};
+
+struct koneplus_roccat_report {
+       uint8_t type;
+       uint8_t data1;
+       uint8_t data2;
+       uint8_t profile;
+} __attribute__ ((__packed__));
+
+struct koneplus_device {
+       int actual_profile;
+
+       int roccat_claimed;
+       int chrdev_minor;
+
+       struct mutex koneplus_lock;
+
+       int startup_profile;
+       struct koneplus_info info;
+       struct koneplus_profile_settings profile_settings[5];
+       struct koneplus_profile_buttons profile_buttons[5];
+};
+
+#endif
index 9bf23047892aefe3c10c1b60a260498c1181f811..02c58e015bee953a03ed5a7b8f48666e53dcec39 100644 (file)
 #include "hid-roccat.h"
 #include "hid-roccat-pyra.h"
 
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+/* pyra_class is used for creating sysfs attributes via roccat char device */
+static struct class *pyra_class;
+
 static void profile_activated(struct pyra_device *pyra,
                unsigned int new_profile)
 {
@@ -87,9 +92,8 @@ static int pyra_receive_control_status(struct usb_device *usb_dev)
                        control.value == 1)
                        return 0;
        else {
-               dev_err(&usb_dev->dev, "receive control status: "
-                               "unknown response 0x%x 0x%x\n",
-                               control.request, control.value);
+               hid_err(usb_dev, "receive control status: unknown response 0x%x 0x%x\n",
+                       control.request, control.value);
                return -EINVAL;
        }
 }
@@ -221,9 +225,10 @@ static int pyra_set_settings(struct usb_device *usb_dev,
 
 static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count, int number)
+               loff_t off, size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
 
        if (off >= sizeof(struct pyra_profile_settings))
@@ -233,58 +238,19 @@ static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
                count = sizeof(struct pyra_profile_settings) - off;
 
        mutex_lock(&pyra->pyra_lock);
-       memcpy(buf, ((char const *)&pyra->profile_settings[number]) + off,
+       memcpy(buf, ((char const *)&pyra->profile_settings[*(uint *)(attr->private)]) + off,
                        count);
        mutex_unlock(&pyra->pyra_lock);
 
        return count;
 }
 
-static ssize_t pyra_sysfs_read_profile1_settings(struct file *fp,
-               struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count)
-{
-       return pyra_sysfs_read_profilex_settings(fp, kobj,
-                       attr, buf, off, count, 0);
-}
-
-static ssize_t pyra_sysfs_read_profile2_settings(struct file *fp,
-               struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count)
-{
-       return pyra_sysfs_read_profilex_settings(fp, kobj,
-                       attr, buf, off, count, 1);
-}
-
-static ssize_t pyra_sysfs_read_profile3_settings(struct file *fp,
-               struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count)
-{
-       return pyra_sysfs_read_profilex_settings(fp, kobj,
-                       attr, buf, off, count, 2);
-}
-
-static ssize_t pyra_sysfs_read_profile4_settings(struct file *fp,
-               struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count)
-{
-       return pyra_sysfs_read_profilex_settings(fp, kobj,
-                       attr, buf, off, count, 3);
-}
-
-static ssize_t pyra_sysfs_read_profile5_settings(struct file *fp,
-               struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count)
-{
-       return pyra_sysfs_read_profilex_settings(fp, kobj,
-                       attr, buf, off, count, 4);
-}
-
 static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count, int number)
+               loff_t off, size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
 
        if (off >= sizeof(struct pyra_profile_buttons))
@@ -294,58 +260,19 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
                count = sizeof(struct pyra_profile_buttons) - off;
 
        mutex_lock(&pyra->pyra_lock);
-       memcpy(buf, ((char const *)&pyra->profile_buttons[number]) + off,
+       memcpy(buf, ((char const *)&pyra->profile_buttons[*(uint *)(attr->private)]) + off,
                        count);
        mutex_unlock(&pyra->pyra_lock);
 
        return count;
 }
 
-static ssize_t pyra_sysfs_read_profile1_buttons(struct file *fp,
-               struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count)
-{
-       return pyra_sysfs_read_profilex_buttons(fp, kobj,
-                       attr, buf, off, count, 0);
-}
-
-static ssize_t pyra_sysfs_read_profile2_buttons(struct file *fp,
-               struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count)
-{
-       return pyra_sysfs_read_profilex_buttons(fp, kobj,
-                       attr, buf, off, count, 1);
-}
-
-static ssize_t pyra_sysfs_read_profile3_buttons(struct file *fp,
-               struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count)
-{
-       return pyra_sysfs_read_profilex_buttons(fp, kobj,
-                       attr, buf, off, count, 2);
-}
-
-static ssize_t pyra_sysfs_read_profile4_buttons(struct file *fp,
-               struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count)
-{
-       return pyra_sysfs_read_profilex_buttons(fp, kobj,
-                       attr, buf, off, count, 3);
-}
-
-static ssize_t pyra_sysfs_read_profile5_buttons(struct file *fp,
-               struct kobject *kobj, struct bin_attribute *attr, char *buf,
-               loff_t off, size_t count)
-{
-       return pyra_sysfs_read_profilex_buttons(fp, kobj,
-                       attr, buf, off, count, 4);
-}
-
 static ssize_t pyra_sysfs_write_profile_settings(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval = 0;
@@ -381,7 +308,8 @@ static ssize_t pyra_sysfs_write_profile_buttons(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval = 0;
@@ -417,7 +345,8 @@ static ssize_t pyra_sysfs_read_settings(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
 
        if (off >= sizeof(struct pyra_settings))
@@ -437,7 +366,8 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev =
+                       container_of(kobj, struct device, kobj)->parent->parent;
        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval = 0;
@@ -469,255 +399,125 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
 static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+       struct pyra_device *pyra =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
        return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi);
 }
 
 static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+       struct pyra_device *pyra =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
        return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile);
 }
 
 static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+       struct pyra_device *pyra =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
        return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version);
 }
 
 static ssize_t pyra_sysfs_show_startup_profile(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+       struct pyra_device *pyra =
+                       hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
        return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile);
 }
 
-static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL);
-
-static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
-
-static DEVICE_ATTR(firmware_version, 0440,
-               pyra_sysfs_show_firmware_version, NULL);
-
-static DEVICE_ATTR(startup_profile, 0440,
-               pyra_sysfs_show_startup_profile, NULL);
-
-static struct attribute *pyra_attributes[] = {
-               &dev_attr_actual_cpi.attr,
-               &dev_attr_actual_profile.attr,
-               &dev_attr_firmware_version.attr,
-               &dev_attr_startup_profile.attr,
-               NULL
-};
-
-static struct attribute_group pyra_attribute_group = {
-               .attrs = pyra_attributes
+static struct device_attribute pyra_attributes[] = {
+       __ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL),
+       __ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL),
+       __ATTR(firmware_version, 0440,
+                       pyra_sysfs_show_firmware_version, NULL),
+       __ATTR(startup_profile, 0440,
+                       pyra_sysfs_show_startup_profile, NULL),
+       __ATTR_NULL
 };
 
-static struct bin_attribute pyra_profile_settings_attr = {
+static struct bin_attribute pyra_bin_attributes[] = {
+       {
                .attr = { .name = "profile_settings", .mode = 0220 },
                .size = sizeof(struct pyra_profile_settings),
                .write = pyra_sysfs_write_profile_settings
-};
-
-static struct bin_attribute pyra_profile1_settings_attr = {
+       },
+       {
                .attr = { .name = "profile1_settings", .mode = 0440 },
                .size = sizeof(struct pyra_profile_settings),
-               .read = pyra_sysfs_read_profile1_settings
-};
-
-static struct bin_attribute pyra_profile2_settings_attr = {
+               .read = pyra_sysfs_read_profilex_settings,
+               .private = &profile_numbers[0]
+       },
+       {
                .attr = { .name = "profile2_settings", .mode = 0440 },
                .size = sizeof(struct pyra_profile_settings),
-               .read = pyra_sysfs_read_profile2_settings
-};
-
-static struct bin_attribute pyra_profile3_settings_attr = {
+               .read = pyra_sysfs_read_profilex_settings,
+               .private = &profile_numbers[1]
+       },
+       {
                .attr = { .name = "profile3_settings", .mode = 0440 },
                .size = sizeof(struct pyra_profile_settings),
-               .read = pyra_sysfs_read_profile3_settings
-};
-
-static struct bin_attribute pyra_profile4_settings_attr = {
+               .read = pyra_sysfs_read_profilex_settings,
+               .private = &profile_numbers[2]
+       },
+       {
                .attr = { .name = "profile4_settings", .mode = 0440 },
                .size = sizeof(struct pyra_profile_settings),
-               .read = pyra_sysfs_read_profile4_settings
-};
-
-static struct bin_attribute pyra_profile5_settings_attr = {
+               .read = pyra_sysfs_read_profilex_settings,
+               .private = &profile_numbers[3]
+       },
+       {
                .attr = { .name = "profile5_settings", .mode = 0440 },
                .size = sizeof(struct pyra_profile_settings),
-               .read = pyra_sysfs_read_profile5_settings
-};
-
-static struct bin_attribute pyra_profile_buttons_attr = {
+               .read = pyra_sysfs_read_profilex_settings,
+               .private = &profile_numbers[4]
+       },
+       {
                .attr = { .name = "profile_buttons", .mode = 0220 },
                .size = sizeof(struct pyra_profile_buttons),
                .write = pyra_sysfs_write_profile_buttons
-};
-
-static struct bin_attribute pyra_profile1_buttons_attr = {
+       },
+       {
                .attr = { .name = "profile1_buttons", .mode = 0440 },
                .size = sizeof(struct pyra_profile_buttons),
-               .read = pyra_sysfs_read_profile1_buttons
-};
-
-static struct bin_attribute pyra_profile2_buttons_attr = {
+               .read = pyra_sysfs_read_profilex_buttons,
+               .private = &profile_numbers[0]
+       },
+       {
                .attr = { .name = "profile2_buttons", .mode = 0440 },
                .size = sizeof(struct pyra_profile_buttons),
-               .read = pyra_sysfs_read_profile2_buttons
-};
-
-static struct bin_attribute pyra_profile3_buttons_attr = {
+               .read = pyra_sysfs_read_profilex_buttons,
+               .private = &profile_numbers[1]
+       },
+       {
                .attr = { .name = "profile3_buttons", .mode = 0440 },
                .size = sizeof(struct pyra_profile_buttons),
-               .read = pyra_sysfs_read_profile3_buttons
-};
-
-static struct bin_attribute pyra_profile4_buttons_attr = {
+               .read = pyra_sysfs_read_profilex_buttons,
+               .private = &profile_numbers[2]
+       },
+       {
                .attr = { .name = "profile4_buttons", .mode = 0440 },
                .size = sizeof(struct pyra_profile_buttons),
-               .read = pyra_sysfs_read_profile4_buttons
-};
-
-static struct bin_attribute pyra_profile5_buttons_attr = {
+               .read = pyra_sysfs_read_profilex_buttons,
+               .private = &profile_numbers[3]
+       },
+       {
                .attr = { .name = "profile5_buttons", .mode = 0440 },
                .size = sizeof(struct pyra_profile_buttons),
-               .read = pyra_sysfs_read_profile5_buttons
-};
-
-static struct bin_attribute pyra_settings_attr = {
+               .read = pyra_sysfs_read_profilex_buttons,
+               .private = &profile_numbers[4]
+       },
+       {
                .attr = { .name = "settings", .mode = 0660 },
                .size = sizeof(struct pyra_settings),
                .read = pyra_sysfs_read_settings,
                .write = pyra_sysfs_write_settings
+       },
+       __ATTR_NULL
 };
 
-static int pyra_create_sysfs_attributes(struct usb_interface *intf)
-{
-       int retval;
-
-       retval = sysfs_create_group(&intf->dev.kobj, &pyra_attribute_group);
-       if (retval)
-               goto exit_1;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile_settings_attr);
-       if (retval)
-               goto exit_2;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile1_settings_attr);
-       if (retval)
-               goto exit_3;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile2_settings_attr);
-       if (retval)
-               goto exit_4;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile3_settings_attr);
-       if (retval)
-               goto exit_5;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile4_settings_attr);
-       if (retval)
-               goto exit_6;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile5_settings_attr);
-       if (retval)
-               goto exit_7;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile_buttons_attr);
-       if (retval)
-               goto exit_8;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile1_buttons_attr);
-       if (retval)
-               goto exit_9;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile2_buttons_attr);
-       if (retval)
-               goto exit_10;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile3_buttons_attr);
-       if (retval)
-               goto exit_11;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile4_buttons_attr);
-       if (retval)
-               goto exit_12;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_profile5_buttons_attr);
-       if (retval)
-               goto exit_13;
-
-       retval = sysfs_create_bin_file(&intf->dev.kobj,
-                       &pyra_settings_attr);
-       if (retval)
-               goto exit_14;
-
-       return 0;
-
-exit_14:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
-exit_13:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
-exit_12:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
-exit_11:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
-exit_10:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
-exit_9:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
-exit_8:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
-exit_7:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
-exit_6:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
-exit_5:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
-exit_4:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
-exit_3:
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
-exit_2:
-       sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
-exit_1:
-       return retval;
-}
-
-static void pyra_remove_sysfs_attributes(struct usb_interface *intf)
-{
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_settings_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
-       sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
-       sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
-}
-
 static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
                struct pyra_device *pyra)
 {
@@ -770,31 +570,24 @@ static int pyra_init_specials(struct hid_device *hdev)
 
                pyra = kzalloc(sizeof(*pyra), GFP_KERNEL);
                if (!pyra) {
-                       dev_err(&hdev->dev, "can't alloc device descriptor\n");
+                       hid_err(hdev, "can't alloc device descriptor\n");
                        return -ENOMEM;
                }
                hid_set_drvdata(hdev, pyra);
 
                retval = pyra_init_pyra_device_struct(usb_dev, pyra);
                if (retval) {
-                       dev_err(&hdev->dev,
-                                       "couldn't init struct pyra_device\n");
+                       hid_err(hdev, "couldn't init struct pyra_device\n");
                        goto exit_free;
                }
 
-               retval = roccat_connect(hdev);
+               retval = roccat_connect(pyra_class, hdev);
                if (retval < 0) {
-                       dev_err(&hdev->dev, "couldn't init char dev\n");
+                       hid_err(hdev, "couldn't init char dev\n");
                } else {
                        pyra->chrdev_minor = retval;
                        pyra->roccat_claimed = 1;
                }
-
-               retval = pyra_create_sysfs_attributes(intf);
-               if (retval) {
-                       dev_err(&hdev->dev, "cannot create sysfs files\n");
-                       goto exit_free;
-               }
        } else {
                hid_set_drvdata(hdev, NULL);
        }
@@ -812,7 +605,6 @@ static void pyra_remove_specials(struct hid_device *hdev)
 
        if (intf->cur_altsetting->desc.bInterfaceProtocol
                        == USB_INTERFACE_PROTOCOL_MOUSE) {
-               pyra_remove_sysfs_attributes(intf);
                pyra = hid_get_drvdata(hdev);
                if (pyra->roccat_claimed)
                        roccat_disconnect(pyra->chrdev_minor);
@@ -826,19 +618,19 @@ static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        retval = hid_parse(hdev);
        if (retval) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto exit;
        }
 
        retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (retval) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto exit;
        }
 
        retval = pyra_init_specials(hdev);
        if (retval) {
-               dev_err(&hdev->dev, "couldn't install mouse\n");
+               hid_err(hdev, "couldn't install mouse\n");
                goto exit_stop;
        }
        return 0;
@@ -952,11 +744,24 @@ static struct hid_driver pyra_driver = {
 
 static int __init pyra_init(void)
 {
-       return hid_register_driver(&pyra_driver);
+       int retval;
+
+       /* class name has to be same as driver name */
+       pyra_class = class_create(THIS_MODULE, "pyra");
+       if (IS_ERR(pyra_class))
+               return PTR_ERR(pyra_class);
+       pyra_class->dev_attrs = pyra_attributes;
+       pyra_class->dev_bin_attrs = pyra_bin_attributes;
+
+       retval = hid_register_driver(&pyra_driver);
+       if (retval)
+               class_destroy(pyra_class);
+       return retval;
 }
 
 static void __exit pyra_exit(void)
 {
+       class_destroy(pyra_class);
        hid_unregister_driver(&pyra_driver);
 }
 
index 22f80a8f26f9e56ea314faa8379f4653fcb6aae6..14cbbe1621e008c6862ec7b0322463c27fff5d19 100644 (file)
 
 #include <linux/types.h>
 
-#pragma pack(push)
-#pragma pack(1)
-
 struct pyra_b {
        uint8_t command; /* PYRA_COMMAND_B */
        uint8_t size; /* always 3 */
        uint8_t unknown; /* 1 */
-};
+} __attribute__ ((__packed__));
 
 struct pyra_control {
        uint8_t command; /* PYRA_COMMAND_CONTROL */
@@ -31,7 +28,7 @@ struct pyra_control {
         */
        uint8_t value; /* Range 0-4 */
        uint8_t request;
-};
+} __attribute__ ((__packed__));
 
 enum pyra_control_requests {
        PYRA_CONTROL_REQUEST_STATUS = 0x00,
@@ -43,7 +40,7 @@ struct pyra_settings {
        uint8_t command; /* PYRA_COMMAND_SETTINGS */
        uint8_t size; /* always 3 */
        uint8_t startup_profile; /* Range 0-4! */
-};
+} __attribute__ ((__packed__));
 
 struct pyra_profile_settings {
        uint8_t command; /* PYRA_COMMAND_PROFILE_SETTINGS */
@@ -58,7 +55,7 @@ struct pyra_profile_settings {
        uint8_t light_effect;
        uint8_t handedness;
        uint16_t checksum; /* byte sum */
-};
+} __attribute__ ((__packed__));
 
 struct pyra_profile_buttons {
        uint8_t command; /* PYRA_COMMAND_PROFILE_BUTTONS */
@@ -66,7 +63,7 @@ struct pyra_profile_buttons {
        uint8_t number; /* Range 0-4 */
        uint8_t buttons[14];
        uint16_t checksum; /* byte sum */
-};
+} __attribute__ ((__packed__));
 
 struct pyra_info {
        uint8_t command; /* PYRA_COMMAND_INFO */
@@ -75,7 +72,7 @@ struct pyra_info {
        uint8_t unknown1; /* always 0 */
        uint8_t unknown2; /* always 1 */
        uint8_t unknown3; /* always 0 */
-};
+} __attribute__ ((__packed__));
 
 enum pyra_commands {
        PYRA_COMMAND_CONTROL = 0x4,
@@ -107,13 +104,13 @@ struct pyra_mouse_event_button {
        uint8_t type;
        uint8_t data1;
        uint8_t data2;
-};
+} __attribute__ ((__packed__));
 
 struct pyra_mouse_event_audio {
        uint8_t report_number; /* always 2 */
        uint8_t type;
        uint8_t unused; /* always 0 */
-};
+} __attribute__ ((__packed__));
 
 /* hid audio controls */
 enum pyra_mouse_event_audio_types {
@@ -167,9 +164,7 @@ struct pyra_roccat_report {
        uint8_t type;
        uint8_t value;
        uint8_t key;
-};
-
-#pragma pack(pop)
+} __attribute__ ((__packed__));
 
 struct pyra_device {
        int actual_profile;
index 5a6879e235ac5264482fe94d3c8976231dbc6c36..a14c579ea781950787365ea3d2d0218defde5ec8 100644 (file)
@@ -21,6 +21,8 @@
  * It is inspired by hidraw, but uses only one circular buffer for all readers.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/cdev.h>
 #include <linux/poll.h>
 #include <linux/sched.h>
@@ -65,7 +67,6 @@ struct roccat_reader {
 };
 
 static int roccat_major;
-static struct class *roccat_class;
 static struct cdev roccat_cdev;
 
 static struct roccat_device *devices[ROCCAT_MAX_DEVICES];
@@ -165,27 +166,22 @@ static int roccat_open(struct inode *inode, struct file *file)
        mutex_lock(&device->readers_lock);
 
        if (!device) {
-               printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
-                               minor);
+               pr_emerg("roccat device with minor %d doesn't exist\n", minor);
                error = -ENODEV;
                goto exit_err;
        }
 
        if (!device->open++) {
                /* power on device on adding first reader */
-               if (device->hid->ll_driver->power) {
-                       error = device->hid->ll_driver->power(device->hid,
-                                       PM_HINT_FULLON);
-                       if (error < 0) {
-                               --device->open;
-                               goto exit_err;
-                       }
+               error = hid_hw_power(device->hid, PM_HINT_FULLON);
+               if (error < 0) {
+                       --device->open;
+                       goto exit_err;
                }
-               error = device->hid->ll_driver->open(device->hid);
+
+               error = hid_hw_open(device->hid);
                if (error < 0) {
-                       if (device->hid->ll_driver->power)
-                               device->hid->ll_driver->power(device->hid,
-                                               PM_HINT_NORMAL);
+                       hid_hw_power(device->hid, PM_HINT_NORMAL);
                        --device->open;
                        goto exit_err;
                }
@@ -218,8 +214,7 @@ static int roccat_release(struct inode *inode, struct file *file)
        device = devices[minor];
        if (!device) {
                mutex_unlock(&devices_lock);
-               printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
-                               minor);
+               pr_emerg("roccat device with minor %d doesn't exist\n", minor);
                return -ENODEV;
        }
 
@@ -231,10 +226,8 @@ static int roccat_release(struct inode *inode, struct file *file)
        if (!--device->open) {
                /* removing last reader */
                if (device->exist) {
-                       if (device->hid->ll_driver->power)
-                               device->hid->ll_driver->power(device->hid,
-                                               PM_HINT_NORMAL);
-                       device->hid->ll_driver->close(device->hid);
+                       hid_hw_power(device->hid, PM_HINT_NORMAL);
+                       hid_hw_close(device->hid);
                } else {
                        kfree(device);
                }
@@ -295,12 +288,14 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
 
 /*
  * roccat_connect() - create a char device for special event output
+ * @class: the class thats used to create the device. Meant to hold device
+ * specific sysfs attributes.
  * @hid: the hid device the char device should be connected to.
  *
  * Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
  * success, a negative error code on failure.
  */
-int roccat_connect(struct hid_device *hid)
+int roccat_connect(struct class *klass, struct hid_device *hid)
 {
        unsigned int minor;
        struct roccat_device *device;
@@ -326,7 +321,7 @@ int roccat_connect(struct hid_device *hid)
                return -EINVAL;
        }
 
-       device->dev = device_create(roccat_class, &hid->dev,
+       device->dev = device_create(klass, &hid->dev,
                        MKDEV(roccat_major, minor), NULL,
                        "%s%s%d", "roccat", hid->driver->name, minor);
 
@@ -367,10 +362,10 @@ void roccat_disconnect(int minor)
 
        device->exist = 0; /* TODO exist maybe not needed */
 
-       device_destroy(roccat_class, MKDEV(roccat_major, minor));
+       device_destroy(device->dev->class, MKDEV(roccat_major, minor));
 
        if (device->open) {
-               device->hid->ll_driver->close(device->hid);
+               hid_hw_close(device->hid);
                wake_up_interruptible(&device->wait);
        } else {
                kfree(device);
@@ -398,14 +393,7 @@ static int __init roccat_init(void)
        roccat_major = MAJOR(dev_id);
 
        if (retval < 0) {
-               printk(KERN_WARNING "roccat: can't get major number\n");
-               return retval;
-       }
-
-       roccat_class = class_create(THIS_MODULE, "roccat");
-       if (IS_ERR(roccat_class)) {
-               retval = PTR_ERR(roccat_class);
-               unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
+               pr_warn("can't get major number\n");
                return retval;
        }
 
@@ -420,7 +408,6 @@ static void __exit roccat_exit(void)
        dev_t dev_id = MKDEV(roccat_major, 0);
 
        cdev_del(&roccat_cdev);
-       class_destroy(roccat_class);
        unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
 }
 
index 09e864e9f79dcbc37f5f4fc9bb5ced38105527d9..5784281d613f0117dfadfa73eca39ea89f70b112 100644 (file)
 #include <linux/types.h>
 
 #if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE)
-int roccat_connect(struct hid_device *hid);
+int roccat_connect(struct class *klass, struct hid_device *hid);
 void roccat_disconnect(int minor);
 int roccat_report_event(int minor, u8 const *data, int len);
 #else
-static inline int roccat_connect(struct hid_device *hid) { return -1; }
+static inline int roccat_connect(struct class *klass,
+               struct hid_device *hid) { return -1; }
 static inline void roccat_disconnect(int minor) {}
 static inline int roccat_report_event(int minor, u8 const *data, int len)
 {
index 35894444e00067640532c17f2cc5468c1f9cef14..3c1fd8af5e0c37495a25e98dbbfc19db9b22bb99 100644 (file)
@@ -57,8 +57,8 @@
 static inline void samsung_irda_dev_trace(struct hid_device *hdev,
                unsigned int rsize)
 {
-       dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report "
-                       "descriptor\n", rsize);
+       hid_info(hdev, "fixing up Samsung IrDA %d byte report descriptor\n",
+                rsize);
 }
 
 static __u8 *samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
@@ -160,7 +160,7 @@ static int samsung_probe(struct hid_device *hdev,
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
@@ -174,7 +174,7 @@ static int samsung_probe(struct hid_device *hdev,
 
        ret = hid_hw_start(hdev, cmask);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
index e10a7687ebf2848e15210bf7466356a060765054..16f7cafc9695b64377b07c5cca95c5bcea52824d 100644 (file)
@@ -74,26 +74,25 @@ static int sjoyff_init(struct hid_device *hid)
        int error;
 
        if (list_empty(report_list)) {
-               dev_err(&hid->dev, "no output reports found\n");
+               hid_err(hid, "no output reports found\n");
                return -ENODEV;
        }
 
        report_ptr = report_ptr->next;
 
        if (report_ptr == report_list) {
-               dev_err(&hid->dev, "required output report is "
-                               "missing\n");
+               hid_err(hid, "required output report is missing\n");
                return -ENODEV;
        }
 
        report = list_entry(report_ptr, struct hid_report, list);
        if (report->maxfield < 1) {
-               dev_err(&hid->dev, "no fields in the report\n");
+               hid_err(hid, "no fields in the report\n");
                return -ENODEV;
        }
 
        if (report->field[0]->report_count < 3) {
-               dev_err(&hid->dev, "not enough values in the field\n");
+               hid_err(hid, "not enough values in the field\n");
                return -ENODEV;
        }
 
@@ -117,8 +116,7 @@ static int sjoyff_init(struct hid_device *hid)
        sjoyff->report->field[0]->value[2] = 0x00;
        usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
 
-       dev_info(&hid->dev,
-               "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
+       hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
 
        return 0;
 }
@@ -135,13 +133,13 @@ static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err;
        }
 
index 677bb3da10e8d4149d5d6583f943f6a767c9d3c1..68d7b36e31e43b800e18542918a21ffa75eb2483 100644 (file)
@@ -40,8 +40,7 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 
        if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
                        *rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
-               dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report "
-                               "descriptor\n");
+               hid_info(hdev, "Fixing up Sony Vaio VGX report descriptor\n");
                rdesc[55] = 0x06;
        }
        return rdesc;
@@ -89,7 +88,7 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
                                 (3 << 8) | 0xf2, ifnum, buf, 17,
                                 USB_CTRL_GET_TIMEOUT);
        if (ret < 0)
-               dev_err(&hdev->dev, "can't set operational mode\n");
+               hid_err(hdev, "can't set operational mode\n");
 
        kfree(buf);
 
@@ -110,7 +109,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        sc = kzalloc(sizeof(*sc), GFP_KERNEL);
        if (sc == NULL) {
-               dev_err(&hdev->dev, "can't alloc sony descriptor\n");
+               hid_err(hdev, "can't alloc sony descriptor\n");
                return -ENOMEM;
        }
 
@@ -119,14 +118,14 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
                        HID_CONNECT_HIDDEV_FORCE);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
index 3171be28c3d534daf8d3a8f245de79a1137fc9a8..b2be1d11916b79aa5f600dedd06fdfe917041707 100644 (file)
@@ -222,7 +222,7 @@ static int stantum_probe(struct hid_device *hdev,
 
        sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL);
        if (!sd) {
-               dev_err(&hdev->dev, "cannot allocate Stantum data\n");
+               hid_err(hdev, "cannot allocate Stantum data\n");
                return -ENOMEM;
        }
        sd->valid = false;
index 164ed568f6cf73bf4640b6f4080d99dde37d6d91..d484a0043dd43572238c3f4b9cb0f84f1e355bfb 100644 (file)
@@ -27,8 +27,7 @@ static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 {
        if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
                        rdesc[106] == 0x03) {
-               dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop "
-                               "report descriptor\n");
+               hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
                rdesc[105] = rdesc[110] = 0x03;
                rdesc[106] = rdesc[111] = 0x21;
        }
index 25be4e1461bde288497ab2ed5363842934a18df4..575862b0688e4e233108f155812a5962dd38177b 100644 (file)
@@ -151,28 +151,23 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
                        switch (field->usage[0].hid) {
                        case THRUSTMASTER_USAGE_FF:
                                if (field->report_count < 2) {
-                                       dev_warn(&hid->dev, "ignoring FF field "
-                                               "with report_count < 2\n");
+                                       hid_warn(hid, "ignoring FF field with report_count < 2\n");
                                        continue;
                                }
 
                                if (field->logical_maximum ==
                                                field->logical_minimum) {
-                                       dev_warn(&hid->dev, "ignoring FF field "
-                                                       "with logical_maximum "
-                                                       "== logical_minimum\n");
+                                       hid_warn(hid, "ignoring FF field with logical_maximum == logical_minimum\n");
                                        continue;
                                }
 
                                if (tmff->report && tmff->report != report) {
-                                       dev_warn(&hid->dev, "ignoring FF field "
-                                                       "in other report\n");
+                                       hid_warn(hid, "ignoring FF field in other report\n");
                                        continue;
                                }
 
                                if (tmff->ff_field && tmff->ff_field != field) {
-                                       dev_warn(&hid->dev, "ignoring "
-                                                       "duplicate FF field\n");
+                                       hid_warn(hid, "ignoring duplicate FF field\n");
                                        continue;
                                }
 
@@ -185,16 +180,15 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
                                break;
 
                        default:
-                               dev_warn(&hid->dev, "ignoring unknown output "
-                                               "usage %08x\n",
-                                               field->usage[0].hid);
+                               hid_warn(hid, "ignoring unknown output usage %08x\n",
+                                        field->usage[0].hid);
                                continue;
                        }
                }
        }
 
        if (!tmff->report) {
-               dev_err(&hid->dev, "can't find FF field in output reports\n");
+               hid_err(hid, "can't find FF field in output reports\n");
                error = -ENODEV;
                goto fail;
        }
@@ -203,8 +197,7 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
        if (error)
                goto fail;
 
-       dev_info(&hid->dev, "force feedback for ThrustMaster devices by Zinx "
-                       "Verituse <zinx@epicsol.org>");
+       hid_info(hid, "force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>\n");
        return 0;
 
 fail:
@@ -224,13 +217,13 @@ static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err;
        }
 
index 956ed9ac19d4dee7fc3b259b1453662ec0bd8146..613ff7b1d746a0d51d56dca6e17e2cc2e0e1e7dc 100644 (file)
@@ -66,6 +66,7 @@ static const struct hid_device_id ts_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, ts_devices);
index 724f46ed612f96320d2d24d60671c2bfa63b91c9..06888323828c3b18a8e162402193eeb6aec72b84 100644 (file)
@@ -18,6 +18,8 @@
  * any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
@@ -141,8 +143,8 @@ static void wacom_poke(struct hid_device *hdev, u8 speed)
         * Note that if the raw queries fail, it's not a hard failure and it
         * is safe to continue
         */
-       dev_warn(&hdev->dev, "failed to poke device, command %d, err %d\n",
-                               rep_data[0], ret);
+       hid_warn(hdev, "failed to poke device, command %d, err %d\n",
+                rep_data[0], ret);
        return;
 }
 
@@ -172,7 +174,7 @@ static ssize_t wacom_store_speed(struct device *dev,
                return -EINVAL;
 }
 
-static DEVICE_ATTR(speed, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
                wacom_show_speed, wacom_store_speed);
 
 static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
@@ -312,7 +314,7 @@ static int wacom_probe(struct hid_device *hdev,
 
        wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
        if (wdata == NULL) {
-               dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
+               hid_err(hdev, "can't alloc wacom descriptor\n");
                return -ENOMEM;
        }
 
@@ -321,20 +323,20 @@ static int wacom_probe(struct hid_device *hdev,
        /* Parse the HID report now */
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
        ret = device_create_file(&hdev->dev, &dev_attr_speed);
        if (ret)
-               dev_warn(&hdev->dev,
-                       "can't create sysfs speed attribute err: %d\n", ret);
+               hid_warn(hdev,
+                        "can't create sysfs speed attribute err: %d\n", ret);
 
        /* Set Wacom mode 2 with high reporting speed */
        wacom_poke(hdev, 1);
@@ -349,8 +351,8 @@ static int wacom_probe(struct hid_device *hdev,
 
        ret = power_supply_register(&hdev->dev, &wdata->battery);
        if (ret) {
-               dev_warn(&hdev->dev,
-                       "can't create sysfs battery attribute, err: %d\n", ret);
+               hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n",
+                        ret);
                /*
                 * battery attribute is not critical for the tablet, but if it
                 * failed then there is no need to create ac attribute
@@ -367,8 +369,8 @@ static int wacom_probe(struct hid_device *hdev,
 
        ret = power_supply_register(&hdev->dev, &wdata->ac);
        if (ret) {
-               dev_warn(&hdev->dev,
-                       "can't create ac battery attribute, err: %d\n", ret);
+               hid_warn(hdev,
+                        "can't create ac battery attribute, err: %d\n", ret);
                /*
                 * ac attribute is not critical for the tablet, but if it
                 * failed then we don't want to battery attribute to exist
@@ -454,7 +456,7 @@ static int __init wacom_init(void)
 
        ret = hid_register_driver(&wacom_driver);
        if (ret)
-               printk(KERN_ERR "can't register wacom driver\n");
+               pr_err("can't register wacom driver\n");
        return ret;
 }
 
index b7acceabba803fe8af9bba278872ed406ab6bff8..f31fab012f2f24732aa7934cc732b9e7b7cffb64 100644 (file)
@@ -75,14 +75,14 @@ static int zpff_init(struct hid_device *hid)
        int error;
 
        if (list_empty(report_list)) {
-               dev_err(&hid->dev, "no output report found\n");
+               hid_err(hid, "no output report found\n");
                return -ENODEV;
        }
 
        report = list_entry(report_list->next, struct hid_report, list);
 
        if (report->maxfield < 4) {
-               dev_err(&hid->dev, "not enough fields in report\n");
+               hid_err(hid, "not enough fields in report\n");
                return -ENODEV;
        }
 
@@ -105,8 +105,7 @@ static int zpff_init(struct hid_device *hid)
        zpff->report->field[3]->value[0] = 0x00;
        usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
 
-       dev_info(&hid->dev, "force feedback for Zeroplus based devices by "
-              "Anssi Hannula <anssi.hannula@gmail.com>\n");
+       hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
 
        return 0;
 }
@@ -123,13 +122,13 @@ static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
        if (ret) {
-               dev_err(&hdev->dev, "hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err;
        }
 
index aac1f92731491083db68e0c212dd1292aed67b74..e90371508fd2bf7a205cc56e31d47f1eda1a084e 100644 (file)
@@ -34,9 +34,8 @@ static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff &&
                rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff &&
                rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) {
-                       dev_info(&hdev->dev,
-                               "fixing up zydacron remote control report "
-                               "descriptor\n");
+                       hid_info(hdev,
+                               "fixing up zydacron remote control report descriptor\n");
                        rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c;
                        rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00;
                }
@@ -172,7 +171,7 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        zc = kzalloc(sizeof(*zc), GFP_KERNEL);
        if (zc == NULL) {
-               dev_err(&hdev->dev, "zydacron: can't alloc descriptor\n");
+               hid_err(hdev, "can't alloc descriptor\n");
                return -ENOMEM;
        }
 
@@ -180,13 +179,13 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret) {
-               dev_err(&hdev->dev, "zydacron: parse failed\n");
+               hid_err(hdev, "parse failed\n");
                goto err_free;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
-               dev_err(&hdev->dev, "zydacron: hw start failed\n");
+               hid_err(hdev, "hw start failed\n");
                goto err_free;
        }
 
index e1f07483691f7823b46db14c38dc0d8daa536a13..468e87b53ed26aadb86ed6b127599ea669a6aa99 100644 (file)
@@ -19,6 +19,8 @@
  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -122,15 +124,15 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
        }
 
        if (count > HID_MAX_BUFFER_SIZE) {
-               printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
-                               task_pid_nr(current));
+               hid_warn(dev, "pid %d passed too large report\n",
+                        task_pid_nr(current));
                ret = -EINVAL;
                goto out;
        }
 
        if (count < 2) {
-               printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
-                               task_pid_nr(current));
+               hid_warn(dev, "pid %d passed too short report\n",
+                        task_pid_nr(current));
                ret = -EINVAL;
                goto out;
        }
@@ -192,15 +194,13 @@ static int hidraw_open(struct inode *inode, struct file *file)
 
        dev = hidraw_table[minor];
        if (!dev->open++) {
-               if (dev->hid->ll_driver->power) {
-                       err = dev->hid->ll_driver->power(dev->hid, PM_HINT_FULLON);
-                       if (err < 0)
-                               goto out_unlock;
-               }
-               err = dev->hid->ll_driver->open(dev->hid);
+               err = hid_hw_power(dev->hid, PM_HINT_FULLON);
+               if (err < 0)
+                       goto out_unlock;
+
+               err = hid_hw_open(dev->hid);
                if (err < 0) {
-                       if (dev->hid->ll_driver->power)
-                               dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
+                       hid_hw_power(dev->hid, PM_HINT_NORMAL);
                        dev->open--;
                }
        }
@@ -229,9 +229,8 @@ static int hidraw_release(struct inode * inode, struct file * file)
        dev = hidraw_table[minor];
        if (!--dev->open) {
                if (list->hidraw->exist) {
-                       if (dev->hid->ll_driver->power)
-                               dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
-                       dev->hid->ll_driver->close(dev->hid);
+                       hid_hw_power(dev->hid, PM_HINT_NORMAL);
+                       hid_hw_close(dev->hid);
                } else {
                        kfree(list->hidraw);
                }
@@ -345,6 +344,9 @@ static const struct file_operations hidraw_ops = {
        .open =         hidraw_open,
        .release =      hidraw_release,
        .unlocked_ioctl = hidraw_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = hidraw_ioctl,
+#endif
        .llseek =       noop_llseek,
 };
 
@@ -433,7 +435,7 @@ void hidraw_disconnect(struct hid_device *hid)
        device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
 
        if (hidraw->open) {
-               hid->ll_driver->close(hid);
+               hid_hw_close(hid);
                wake_up_interruptible(&hidraw->wait);
        } else {
                kfree(hidraw);
@@ -452,7 +454,7 @@ int __init hidraw_init(void)
        hidraw_major = MAJOR(dev_id);
 
        if (result < 0) {
-               printk(KERN_WARNING "hidraw: can't get major number\n");
+               pr_warn("can't get major number\n");
                result = 0;
                goto out;
        }
index 1329ecb37a1c7b8b4e0c24f4f3ce341b4e188061..db3cf31c6fa133fb1356f1f4648291a4ea4b46a0 100644 (file)
@@ -3,15 +3,15 @@
 #
 
 # Multipart objects.
-usbhid-objs    := hid-core.o hid-quirks.o
+usbhid-y       := hid-core.o hid-quirks.o
 
 # Optional parts of multipart objects.
 
 ifeq ($(CONFIG_USB_HIDDEV),y)
-       usbhid-objs     += hiddev.o
+       usbhid-y        += hiddev.o
 endif
 ifeq ($(CONFIG_HID_PID),y)
-       usbhid-objs     += hid-pidff.o
+       usbhid-y        += hid-pidff.o
 endif
 
 obj-$(CONFIG_USB_HID)          += usbhid.o
index 5489eab3a6bd09e9aaf443cc7961f52267aff4a6..b336dd84036f403abdc7891b8e9bb2592dc5705c 100644 (file)
@@ -67,7 +67,6 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
  * Input submission and I/O error handler.
  */
 static DEFINE_MUTEX(hid_open_mut);
-static struct workqueue_struct *resumption_waker;
 
 static void hid_io_error(struct hid_device *hid);
 static int hid_submit_out(struct hid_device *hid);
@@ -136,10 +135,10 @@ static void hid_reset(struct work_struct *work)
                        hid_io_error(hid);
                break;
        default:
-               err_hid("can't reset device, %s-%s/input%d, status %d",
-                               hid_to_usb_dev(hid)->bus->bus_name,
-                               hid_to_usb_dev(hid)->devpath,
-                               usbhid->ifnum, rc);
+               hid_err(hid, "can't reset device, %s-%s/input%d, status %d\n",
+                       hid_to_usb_dev(hid)->bus->bus_name,
+                       hid_to_usb_dev(hid)->devpath,
+                       usbhid->ifnum, rc);
                /* FALLTHROUGH */
        case -EHOSTUNREACH:
        case -ENODEV:
@@ -278,18 +277,18 @@ static void hid_irq_in(struct urb *urb)
                hid_io_error(hid);
                return;
        default:                /* error */
-               dev_warn(&urb->dev->dev, "input irq status %d  "
-                               "received\n", urb->status);
+               hid_warn(urb->dev, "input irq status %d received\n",
+                        urb->status);
        }
 
        status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status) {
                clear_bit(HID_IN_RUNNING, &usbhid->iofl);
                if (status != -EPERM) {
-                       err_hid("can't resubmit intr, %s-%s/input%d, status %d",
-                                       hid_to_usb_dev(hid)->bus->bus_name,
-                                       hid_to_usb_dev(hid)->devpath,
-                                       usbhid->ifnum, status);
+                       hid_err(hid, "can't resubmit intr, %s-%s/input%d, status %d\n",
+                               hid_to_usb_dev(hid)->bus->bus_name,
+                               hid_to_usb_dev(hid)->devpath,
+                               usbhid->ifnum, status);
                        hid_io_error(hid);
                }
        }
@@ -300,10 +299,19 @@ static int hid_submit_out(struct hid_device *hid)
        struct hid_report *report;
        char *raw_report;
        struct usbhid_device *usbhid = hid->driver_data;
+       int r;
 
        report = usbhid->out[usbhid->outtail].report;
        raw_report = usbhid->out[usbhid->outtail].raw_report;
 
+       r = usb_autopm_get_interface_async(usbhid->intf);
+       if (r < 0)
+               return -1;
+
+       /*
+        * if the device hasn't been woken, we leave the output
+        * to resume()
+        */
        if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
                usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
                usbhid->urbout->dev = hid_to_usb_dev(hid);
@@ -313,17 +321,11 @@ static int hid_submit_out(struct hid_device *hid)
                dbg_hid("submitting out urb\n");
 
                if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
-                       err_hid("usb_submit_urb(out) failed");
+                       hid_err(hid, "usb_submit_urb(out) failed\n");
+                       usb_autopm_put_interface_async(usbhid->intf);
                        return -1;
                }
                usbhid->last_out = jiffies;
-       } else {
-               /*
-                * queue work to wake up the device.
-                * as the work queue is freezeable, this is safe
-                * with respect to STD and STR
-                */
-               queue_work(resumption_waker, &usbhid->restart_work);
        }
 
        return 0;
@@ -334,13 +336,16 @@ static int hid_submit_ctrl(struct hid_device *hid)
        struct hid_report *report;
        unsigned char dir;
        char *raw_report;
-       int len;
+       int len, r;
        struct usbhid_device *usbhid = hid->driver_data;
 
        report = usbhid->ctrl[usbhid->ctrltail].report;
        raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
        dir = usbhid->ctrl[usbhid->ctrltail].dir;
 
+       r = usb_autopm_get_interface_async(usbhid->intf);
+       if (r < 0)
+               return -1;
        if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
                len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
                if (dir == USB_DIR_OUT) {
@@ -375,17 +380,11 @@ static int hid_submit_ctrl(struct hid_device *hid)
                        usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
 
                if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
-                       err_hid("usb_submit_urb(ctrl) failed");
+                       usb_autopm_put_interface_async(usbhid->intf);
+                       hid_err(hid, "usb_submit_urb(ctrl) failed\n");
                        return -1;
                }
                usbhid->last_ctrl = jiffies;
-       } else {
-               /*
-                * queue work to wake up the device.
-                * as the work queue is freezeable, this is safe
-                * with respect to STD and STR
-                */
-               queue_work(resumption_waker, &usbhid->restart_work);
        }
 
        return 0;
@@ -413,8 +412,8 @@ static void hid_irq_out(struct urb *urb)
        case -ENOENT:
                break;
        default:                /* error */
-               dev_warn(&urb->dev->dev, "output irq status %d "
-                               "received\n", urb->status);
+               hid_warn(urb->dev, "output irq status %d received\n",
+                        urb->status);
        }
 
        spin_lock_irqsave(&usbhid->lock, flags);
@@ -435,6 +434,7 @@ static void hid_irq_out(struct urb *urb)
 
        clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
        spin_unlock_irqrestore(&usbhid->lock, flags);
+       usb_autopm_put_interface_async(usbhid->intf);
        wake_up(&usbhid->wait);
 }
 
@@ -466,8 +466,7 @@ static void hid_ctrl(struct urb *urb)
        case -EPIPE:            /* report not available */
                break;
        default:                /* error */
-               dev_warn(&urb->dev->dev, "ctrl urb status %d "
-                               "received\n", status);
+               hid_warn(urb->dev, "ctrl urb status %d received\n", status);
        }
 
        if (unplug)
@@ -481,11 +480,13 @@ static void hid_ctrl(struct urb *urb)
                        wake_up(&usbhid->wait);
                }
                spin_unlock(&usbhid->lock);
+               usb_autopm_put_interface_async(usbhid->intf);
                return;
        }
 
        clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
        spin_unlock(&usbhid->lock);
+       usb_autopm_put_interface_async(usbhid->intf);
        wake_up(&usbhid->wait);
 }
 
@@ -501,13 +502,13 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
 
        if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
                if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
-                       dev_warn(&hid->dev, "output queue full\n");
+                       hid_warn(hid, "output queue full\n");
                        return;
                }
 
                usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
                if (!usbhid->out[usbhid->outhead].raw_report) {
-                       dev_warn(&hid->dev, "output queueing failed\n");
+                       hid_warn(hid, "output queueing failed\n");
                        return;
                }
                hid_output_report(report, usbhid->out[usbhid->outhead].raw_report);
@@ -532,14 +533,14 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
        }
 
        if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
-               dev_warn(&hid->dev, "control queue full\n");
+               hid_warn(hid, "control queue full\n");
                return;
        }
 
        if (dir == USB_DIR_OUT) {
                usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
                if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
-                       dev_warn(&hid->dev, "control queueing failed\n");
+                       hid_warn(hid, "control queueing failed\n");
                        return;
                }
                hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report);
@@ -590,7 +591,7 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un
                return -1;
 
        if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
-               dev_warn(&dev->dev, "event field not found\n");
+               hid_warn(dev, "event field not found\n");
                return -1;
        }
 
@@ -656,7 +657,7 @@ int usbhid_open(struct hid_device *hid)
        mutex_lock(&hid_open_mut);
        if (!hid->open++) {
                res = usb_autopm_get_interface(usbhid->intf);
-               /* the device must be awake to reliable request remote wakeup */
+               /* the device must be awake to reliably request remote wakeup */
                if (res < 0) {
                        hid->open--;
                        mutex_unlock(&hid_open_mut);
@@ -722,7 +723,7 @@ void usbhid_init_reports(struct hid_device *hid)
        }
 
        if (err)
-               dev_warn(&hid->dev, "timeout initializing reports\n");
+               hid_warn(hid, "timeout initializing reports\n");
 }
 
 /*
@@ -857,18 +858,6 @@ static void usbhid_restart_queues(struct usbhid_device *usbhid)
        usbhid_restart_ctrl_queue(usbhid);
 }
 
-static void __usbhid_restart_queues(struct work_struct *work)
-{
-       struct usbhid_device *usbhid =
-               container_of(work, struct usbhid_device, restart_work);
-       int r;
-
-       r = usb_autopm_get_interface(usbhid->intf);
-       if (r < 0)
-               return;
-       usb_autopm_put_interface(usbhid->intf);
-}
-
 static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
@@ -1140,8 +1129,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
                if (usb_endpoint_is_int_in(&interface->endpoint[n].desc))
                        has_in++;
        if (!has_in) {
-               dev_err(&intf->dev, "couldn't find an input interrupt "
-                               "endpoint\n");
+               hid_err(intf, "couldn't find an input interrupt endpoint\n");
                return -ENODEV;
        }
 
@@ -1206,14 +1194,13 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
 
        init_waitqueue_head(&usbhid->wait);
        INIT_WORK(&usbhid->reset_work, hid_reset);
-       INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues);
        setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
        spin_lock_init(&usbhid->lock);
 
        ret = hid_add_device(hid);
        if (ret) {
                if (ret != -ENODEV)
-                       dev_err(&intf->dev, "can't add hid device: %d\n", ret);
+                       hid_err(intf, "can't add hid device: %d\n", ret);
                goto err_free;
        }
 
@@ -1241,7 +1228,6 @@ static void usbhid_disconnect(struct usb_interface *intf)
 static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
 {
        del_timer_sync(&usbhid->io_retry);
-       cancel_work_sync(&usbhid->restart_work);
        cancel_work_sync(&usbhid->reset_work);
 }
 
@@ -1262,7 +1248,6 @@ static int hid_pre_reset(struct usb_interface *intf)
        spin_lock_irq(&usbhid->lock);
        set_bit(HID_RESET_PENDING, &usbhid->iofl);
        spin_unlock_irq(&usbhid->lock);
-       cancel_work_sync(&usbhid->restart_work);
        hid_cease_io(usbhid);
 
        return 0;
@@ -1461,9 +1446,6 @@ static int __init hid_init(void)
 {
        int retval = -ENOMEM;
 
-       resumption_waker = create_freezeable_workqueue("usbhid_resumer");
-       if (!resumption_waker)
-               goto no_queue;
        retval = hid_register_driver(&hid_usb_driver);
        if (retval)
                goto hid_register_fail;
@@ -1481,8 +1463,6 @@ usb_register_fail:
 usbhid_quirks_init_fail:
        hid_unregister_driver(&hid_usb_driver);
 hid_register_fail:
-       destroy_workqueue(resumption_waker);
-no_queue:
        return retval;
 }
 
@@ -1491,7 +1471,6 @@ static void __exit hid_exit(void)
        usb_deregister(&hid_driver);
        usbhid_quirks_exit();
        hid_unregister_driver(&hid_usb_driver);
-       destroy_workqueue(resumption_waker);
 }
 
 module_init(hid_init);
index ef381d79cfa81e969b14fcb3fd62cabde2dbb272..f91c136821f7097e05cd761ed9f554a56fabcfed 100644 (file)
@@ -22,7 +22,7 @@
 
 /* #define DEBUG */
 
-#define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg)
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/input.h>
 #include <linux/slab.h>
@@ -220,7 +220,7 @@ static int pidff_rescale_signed(int i, struct hid_field *field)
 static void pidff_set(struct pidff_usage *usage, u16 value)
 {
        usage->value[0] = pidff_rescale(value, 0xffff, usage->field);
-       debug("calculated from %d to %d", value, usage->value[0]);
+       pr_debug("calculated from %d to %d\n", value, usage->value[0]);
 }
 
 static void pidff_set_signed(struct pidff_usage *usage, s16 value)
@@ -235,7 +235,7 @@ static void pidff_set_signed(struct pidff_usage *usage, s16 value)
                        usage->value[0] =
                            pidff_rescale(value, 0x7fff, usage->field);
        }
-       debug("calculated from %d to %d", value, usage->value[0]);
+       pr_debug("calculated from %d to %d\n", value, usage->value[0]);
 }
 
 /*
@@ -259,8 +259,9 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
        pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;
        pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length;
 
-       debug("attack %u => %d", envelope->attack_level,
-             pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
+       hid_dbg(pidff->hid, "attack %u => %d\n",
+               envelope->attack_level,
+               pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
 
        usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
                          USB_DIR_OUT);
@@ -466,33 +467,33 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
        pidff->create_new_effect_type->value[0] = efnum;
        usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
                          USB_DIR_OUT);
-       debug("create_new_effect sent, type: %d", efnum);
+       hid_dbg(pidff->hid, "create_new_effect sent, type: %d\n", efnum);
 
        pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
        pidff->block_load_status->value[0] = 0;
        usbhid_wait_io(pidff->hid);
 
        for (j = 0; j < 60; j++) {
-               debug("pid_block_load requested");
+               hid_dbg(pidff->hid, "pid_block_load requested\n");
                usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
                                  USB_DIR_IN);
                usbhid_wait_io(pidff->hid);
                if (pidff->block_load_status->value[0] ==
                    pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
-                       debug("device reported free memory: %d bytes",
-                             pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
-                               pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
+                       hid_dbg(pidff->hid, "device reported free memory: %d bytes\n",
+                                pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+                                pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
                        return 0;
                }
                if (pidff->block_load_status->value[0] ==
                    pidff->status_id[PID_BLOCK_LOAD_FULL]) {
-                       debug("not enough memory free: %d bytes",
-                             pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+                       hid_dbg(pidff->hid, "not enough memory free: %d bytes\n",
+                               pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
                                pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
                        return -ENOSPC;
                }
        }
-       printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n");
+       hid_err(pidff->hid, "pid_block_load failed 60 times\n");
        return -EIO;
 }
 
@@ -546,7 +547,8 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id)
        struct pidff_device *pidff = dev->ff->private;
        int pid_id = pidff->pid_id[effect_id];
 
-       debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
+       hid_dbg(pidff->hid, "starting to erase %d/%d\n",
+               effect_id, pidff->pid_id[effect_id]);
        /* Wait for the queue to clear. We do not want a full fifo to
           prevent the effect removal. */
        usbhid_wait_io(pidff->hid);
@@ -604,8 +606,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
                                type_id = PID_SAW_DOWN;
                                break;
                        default:
-                               printk(KERN_ERR
-                                      "hid-pidff: invalid waveform\n");
+                               hid_err(pidff->hid, "invalid waveform\n");
                                return -EINVAL;
                        }
 
@@ -696,7 +697,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
                break;
 
        default:
-               printk(KERN_ERR "hid-pidff: invalid type\n");
+               hid_err(pidff->hid, "invalid type\n");
                return -EINVAL;
        }
 
@@ -704,7 +705,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
                pidff->pid_id[effect->id] =
                    pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
 
-       debug("uploaded");
+       hid_dbg(pidff->hid, "uploaded\n");
 
        return 0;
 }
@@ -770,14 +771,14 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
                for (i = 0; i < report->maxfield; i++) {
                        if (report->field[i]->maxusage !=
                            report->field[i]->report_count) {
-                               debug("maxusage and report_count do not match, "
-                                     "skipping");
+                               pr_debug("maxusage and report_count do not match, skipping\n");
                                continue;
                        }
                        for (j = 0; j < report->field[i]->maxusage; j++) {
                                if (report->field[i]->usage[j].hid ==
                                    (HID_UP_PID | table[k])) {
-                                       debug("found %d at %d->%d", k, i, j);
+                                       pr_debug("found %d at %d->%d\n",
+                                                k, i, j);
                                        usage[k].field = report->field[i];
                                        usage[k].value =
                                                &report->field[i]->value[j];
@@ -789,7 +790,7 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
                                break;
                }
                if (!found && strict) {
-                       debug("failed to locate %d", k);
+                       pr_debug("failed to locate %d\n", k);
                        return -1;
                }
        }
@@ -826,8 +827,8 @@ static void pidff_find_reports(struct hid_device *hid, int report_type,
                        continue;
                ret = pidff_check_usage(report->field[0]->logical);
                if (ret != -1) {
-                       debug("found usage 0x%02x from field->logical",
-                             pidff_reports[ret]);
+                       hid_dbg(hid, "found usage 0x%02x from field->logical\n",
+                               pidff_reports[ret]);
                        pidff->reports[ret] = report;
                        continue;
                }
@@ -845,8 +846,9 @@ static void pidff_find_reports(struct hid_device *hid, int report_type,
                        continue;
                ret = pidff_check_usage(hid->collection[i - 1].usage);
                if (ret != -1 && !pidff->reports[ret]) {
-                       debug("found usage 0x%02x from collection array",
-                             pidff_reports[ret]);
+                       hid_dbg(hid,
+                               "found usage 0x%02x from collection array\n",
+                               pidff_reports[ret]);
                        pidff->reports[ret] = report;
                }
        }
@@ -861,7 +863,7 @@ static int pidff_reports_ok(struct pidff_device *pidff)
 
        for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {
                if (!pidff->reports[i]) {
-                       debug("%d missing", i);
+                       hid_dbg(pidff->hid, "%d missing\n", i);
                        return 0;
                }
        }
@@ -884,8 +886,7 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report,
                            report->field[i]->logical_minimum == 1)
                                return report->field[i];
                        else {
-                               printk(KERN_ERR "hid-pidff: logical_minimum "
-                                       "is not 1 as it should be\n");
+                               pr_err("logical_minimum is not 1 as it should be\n");
                                return NULL;
                        }
                }
@@ -924,7 +925,7 @@ static int pidff_find_special_keys(int *keys, struct hid_field *fld,
  */
 static int pidff_find_special_fields(struct pidff_device *pidff)
 {
-       debug("finding special fields");
+       hid_dbg(pidff->hid, "finding special fields\n");
 
        pidff->create_new_effect_type =
                pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT],
@@ -945,32 +946,30 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
                pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION],
                                         0x78, 1);
 
-       debug("search done");
+       hid_dbg(pidff->hid, "search done\n");
 
        if (!pidff->create_new_effect_type || !pidff->set_effect_type) {
-               printk(KERN_ERR "hid-pidff: effect lists not found\n");
+               hid_err(pidff->hid, "effect lists not found\n");
                return -1;
        }
 
        if (!pidff->effect_direction) {
-               printk(KERN_ERR "hid-pidff: direction field not found\n");
+               hid_err(pidff->hid, "direction field not found\n");
                return -1;
        }
 
        if (!pidff->device_control) {
-               printk(KERN_ERR "hid-pidff: device control field not found\n");
+               hid_err(pidff->hid, "device control field not found\n");
                return -1;
        }
 
        if (!pidff->block_load_status) {
-               printk(KERN_ERR
-                      "hid-pidff: block load status field not found\n");
+               hid_err(pidff->hid, "block load status field not found\n");
                return -1;
        }
 
        if (!pidff->effect_operation_status) {
-               printk(KERN_ERR
-                      "hid-pidff: effect operation field not found\n");
+               hid_err(pidff->hid, "effect operation field not found\n");
                return -1;
        }
 
@@ -982,23 +981,22 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
 
        if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type,
                                     effect_types)) {
-               printk(KERN_ERR "hid-pidff: no effect types found\n");
+               hid_err(pidff->hid, "no effect types found\n");
                return -1;
        }
 
        if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status,
                                    block_load_status) !=
                        sizeof(pidff_block_load_status)) {
-               printk(KERN_ERR
-                      "hidpidff: block load status identifiers not found\n");
+               hid_err(pidff->hid,
+                       "block load status identifiers not found\n");
                return -1;
        }
 
        if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status,
                                    effect_operation_status) !=
                        sizeof(pidff_effect_operation_status)) {
-               printk(KERN_ERR
-                      "hidpidff: effect operation identifiers not found\n");
+               hid_err(pidff->hid, "effect operation identifiers not found\n");
                return -1;
        }
 
@@ -1017,8 +1015,8 @@ static int pidff_find_effects(struct pidff_device *pidff,
                int pidff_type = pidff->type_id[i];
                if (pidff->set_effect_type->usage[pidff_type].hid !=
                    pidff->create_new_effect_type->usage[pidff_type].hid) {
-                       printk(KERN_ERR "hid-pidff: "
-                              "effect type number %d is invalid\n", i);
+                       hid_err(pidff->hid,
+                               "effect type number %d is invalid\n", i);
                        return -1;
                }
        }
@@ -1073,27 +1071,23 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
        int envelope_ok = 0;
 
        if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
-               printk(KERN_ERR
-                      "hid-pidff: unknown set_effect report layout\n");
+               hid_err(pidff->hid, "unknown set_effect report layout\n");
                return -ENODEV;
        }
 
        PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
        if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
-               printk(KERN_ERR
-                      "hid-pidff: unknown pid_block_load report layout\n");
+               hid_err(pidff->hid, "unknown pid_block_load report layout\n");
                return -ENODEV;
        }
 
        if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) {
-               printk(KERN_ERR
-                      "hid-pidff: unknown effect_operation report layout\n");
+               hid_err(pidff->hid, "unknown effect_operation report layout\n");
                return -ENODEV;
        }
 
        if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) {
-               printk(KERN_ERR
-                      "hid-pidff: unknown pid_block_free report layout\n");
+               hid_err(pidff->hid, "unknown pid_block_free report layout\n");
                return -ENODEV;
        }
 
@@ -1105,27 +1099,26 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
 
        if (!envelope_ok) {
                if (test_and_clear_bit(FF_CONSTANT, dev->ffbit))
-                       printk(KERN_WARNING "hid-pidff: "
-                              "has constant effect but no envelope\n");
+                       hid_warn(pidff->hid,
+                                "has constant effect but no envelope\n");
                if (test_and_clear_bit(FF_RAMP, dev->ffbit))
-                       printk(KERN_WARNING "hid-pidff: "
-                               "has ramp effect but no envelope\n");
+                       hid_warn(pidff->hid,
+                                "has ramp effect but no envelope\n");
 
                if (test_and_clear_bit(FF_PERIODIC, dev->ffbit))
-                       printk(KERN_WARNING "hid-pidff: "
-                               "has periodic effect but no envelope\n");
+                       hid_warn(pidff->hid,
+                                "has periodic effect but no envelope\n");
        }
 
        if (test_bit(FF_CONSTANT, dev->ffbit) &&
            PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) {
-               printk(KERN_WARNING
-                      "hid-pidff: unknown constant effect layout\n");
+               hid_warn(pidff->hid, "unknown constant effect layout\n");
                clear_bit(FF_CONSTANT, dev->ffbit);
        }
 
        if (test_bit(FF_RAMP, dev->ffbit) &&
            PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) {
-               printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n");
+               hid_warn(pidff->hid, "unknown ramp effect layout\n");
                clear_bit(FF_RAMP, dev->ffbit);
        }
 
@@ -1134,8 +1127,7 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
             test_bit(FF_FRICTION, dev->ffbit) ||
             test_bit(FF_INERTIA, dev->ffbit)) &&
            PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
-               printk(KERN_WARNING
-                      "hid-pidff: unknown condition effect layout\n");
+               hid_warn(pidff->hid, "unknown condition effect layout\n");
                clear_bit(FF_SPRING, dev->ffbit);
                clear_bit(FF_DAMPER, dev->ffbit);
                clear_bit(FF_FRICTION, dev->ffbit);
@@ -1144,8 +1136,7 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
 
        if (test_bit(FF_PERIODIC, dev->ffbit) &&
            PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) {
-               printk(KERN_WARNING
-                      "hid-pidff: unknown periodic effect layout\n");
+               hid_warn(pidff->hid, "unknown periodic effect layout\n");
                clear_bit(FF_PERIODIC, dev->ffbit);
        }
 
@@ -1184,12 +1175,12 @@ static void pidff_reset(struct pidff_device *pidff)
        if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
                while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) {
                        if (i++ > 20) {
-                               printk(KERN_WARNING "hid-pidff: device reports "
-                                      "%d simultaneous effects\n",
-                                      pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
+                               hid_warn(pidff->hid,
+                                        "device reports %d simultaneous effects\n",
+                                        pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
                                break;
                        }
-                       debug("pid_pool requested again");
+                       hid_dbg(pidff->hid, "pid_pool requested again\n");
                        usbhid_submit_report(hid, pidff->reports[PID_POOL],
                                          USB_DIR_IN);
                        usbhid_wait_io(hid);
@@ -1215,7 +1206,7 @@ static int pidff_check_autocenter(struct pidff_device *pidff,
 
        error = pidff_request_effect_upload(pidff, 1);
        if (error) {
-               printk(KERN_ERR "hid-pidff: upload request failed\n");
+               hid_err(pidff->hid, "upload request failed\n");
                return error;
        }
 
@@ -1224,8 +1215,8 @@ static int pidff_check_autocenter(struct pidff_device *pidff,
                pidff_autocenter(pidff, 0xffff);
                set_bit(FF_AUTOCENTER, dev->ffbit);
        } else {
-               printk(KERN_NOTICE "hid-pidff: "
-                      "device has unknown autocenter control method\n");
+               hid_notice(pidff->hid,
+                          "device has unknown autocenter control method\n");
        }
 
        pidff_erase_pid(pidff,
@@ -1248,10 +1239,10 @@ int hid_pidff_init(struct hid_device *hid)
        int max_effects;
        int error;
 
-       debug("starting pid init");
+       hid_dbg(hid, "starting pid init\n");
 
        if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
-               debug("not a PID device, no output report");
+               hid_dbg(hid, "not a PID device, no output report\n");
                return -ENODEV;
        }
 
@@ -1265,7 +1256,7 @@ int hid_pidff_init(struct hid_device *hid)
        pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
 
        if (!pidff_reports_ok(pidff)) {
-               debug("reports not ok, aborting");
+               hid_dbg(hid, "reports not ok, aborting\n");
                error = -ENODEV;
                goto fail;
        }
@@ -1278,8 +1269,8 @@ int hid_pidff_init(struct hid_device *hid)
 
        if (test_bit(FF_GAIN, dev->ffbit)) {
                pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
-               usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
-                                 USB_DIR_OUT);
+               usbhid_submit_report(hid, pidff->reports[PID_DEVICE_GAIN],
+                                    USB_DIR_OUT);
        }
 
        error = pidff_check_autocenter(pidff, dev);
@@ -1290,23 +1281,23 @@ int hid_pidff_init(struct hid_device *hid)
            pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum -
            pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum +
            1;
-       debug("max effects is %d", max_effects);
+       hid_dbg(hid, "max effects is %d\n", max_effects);
 
        if (max_effects > PID_EFFECTS_MAX)
                max_effects = PID_EFFECTS_MAX;
 
        if (pidff->pool[PID_SIMULTANEOUS_MAX].value)
-               debug("max simultaneous effects is %d",
-                     pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
+               hid_dbg(hid, "max simultaneous effects is %d\n",
+                       pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
 
        if (pidff->pool[PID_RAM_POOL_SIZE].value)
-               debug("device memory size is %d bytes",
-                     pidff->pool[PID_RAM_POOL_SIZE].value[0]);
+               hid_dbg(hid, "device memory size is %d bytes\n",
+                       pidff->pool[PID_RAM_POOL_SIZE].value[0]);
 
        if (pidff->pool[PID_DEVICE_MANAGED_POOL].value &&
            pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) {
-               printk(KERN_NOTICE "hid-pidff: "
-                      "device does not support device managed pool\n");
+               hid_notice(hid,
+                          "device does not support device managed pool\n");
                goto fail;
        }
 
@@ -1322,8 +1313,7 @@ int hid_pidff_init(struct hid_device *hid)
        ff->set_autocenter = pidff_set_autocenter;
        ff->playback = pidff_playback;
 
-       printk(KERN_INFO "Force feedback for USB HID PID devices by "
-              "Anssi Hannula <anssi.hannula@gmail.com>\n");
+       hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
 
        return 0;
 
index 2c185477eeb3f7a61bdcdcd757ef5fcb728443f5..76b9a149c7df6b46d7d990e7e5a27144ea78fced 100644 (file)
@@ -85,7 +85,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
 
        { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
-
+       { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
        { 0, 0 }
 };
 
index 984feb351a5a3205de716fdb68ad9e5f983bdadd..af0a7c1002af7d97cf97379901341f561cbeff90 100644 (file)
@@ -585,163 +585,168 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct hiddev_list *list = file->private_data;
        struct hiddev *hiddev = list->hiddev;
-       struct hid_device *hid = hiddev->hid;
-       struct usb_device *dev;
+       struct hid_device *hid;
        struct hiddev_collection_info cinfo;
        struct hiddev_report_info rinfo;
        struct hiddev_field_info finfo;
        struct hiddev_devinfo dinfo;
        struct hid_report *report;
        struct hid_field *field;
-       struct usbhid_device *usbhid = hid->driver_data;
        void __user *user_arg = (void __user *)arg;
-       int i, r;
-       
+       int i, r = -EINVAL;
+
        /* Called without BKL by compat methods so no BKL taken */
 
-       /* FIXME: Who or what stop this racing with a disconnect ?? */
-       if (!hiddev->exist || !hid)
-               return -EIO;
+       mutex_lock(&hiddev->existancelock);
+       if (!hiddev->exist) {
+               r = -ENODEV;
+               goto ret_unlock;
+       }
 
-       dev = hid_to_usb_dev(hid);
+       hid = hiddev->hid;
 
        switch (cmd) {
 
        case HIDIOCGVERSION:
-               return put_user(HID_VERSION, (int __user *)arg);
+               r = put_user(HID_VERSION, (int __user *)arg) ?
+                       -EFAULT : 0;
+               break;
 
        case HIDIOCAPPLICATION:
                if (arg < 0 || arg >= hid->maxapplication)
-                       return -EINVAL;
+                       break;
 
                for (i = 0; i < hid->maxcollection; i++)
                        if (hid->collection[i].type ==
                            HID_COLLECTION_APPLICATION && arg-- == 0)
                                break;
 
-               if (i == hid->maxcollection)
-                       return -EINVAL;
-
-               return hid->collection[i].usage;
+               if (i < hid->maxcollection)
+                       r = hid->collection[i].usage;
+               break;
 
        case HIDIOCGDEVINFO:
-               dinfo.bustype = BUS_USB;
-               dinfo.busnum = dev->bus->busnum;
-               dinfo.devnum = dev->devnum;
-               dinfo.ifnum = usbhid->ifnum;
-               dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
-               dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
-               dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
-               dinfo.num_applications = hid->maxapplication;
-               if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
-                       return -EFAULT;
-
-               return 0;
+               {
+                       struct usb_device *dev = hid_to_usb_dev(hid);
+                       struct usbhid_device *usbhid = hid->driver_data;
+
+                       dinfo.bustype = BUS_USB;
+                       dinfo.busnum = dev->bus->busnum;
+                       dinfo.devnum = dev->devnum;
+                       dinfo.ifnum = usbhid->ifnum;
+                       dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
+                       dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
+                       dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
+                       dinfo.num_applications = hid->maxapplication;
+
+                       r = copy_to_user(user_arg, &dinfo, sizeof(dinfo)) ?
+                               -EFAULT : 0;
+                       break;
+               }
 
        case HIDIOCGFLAG:
-               if (put_user(list->flags, (int __user *)arg))
-                       return -EFAULT;
-
-               return 0;
+               r = put_user(list->flags, (int __user *)arg) ?
+                       -EFAULT : 0;
+               break;
 
        case HIDIOCSFLAG:
                {
                        int newflags;
-                       if (get_user(newflags, (int __user *)arg))
-                               return -EFAULT;
+
+                       if (get_user(newflags, (int __user *)arg)) {
+                               r = -EFAULT;
+                               break;
+                       }
 
                        if ((newflags & ~HIDDEV_FLAGS) != 0 ||
                            ((newflags & HIDDEV_FLAG_REPORT) != 0 &&
                             (newflags & HIDDEV_FLAG_UREF) == 0))
-                               return -EINVAL;
+                               break;
 
                        list->flags = newflags;
 
-                       return 0;
+                       r = 0;
+                       break;
                }
 
        case HIDIOCGSTRING:
-               mutex_lock(&hiddev->existancelock);
-               if (hiddev->exist)
-                       r = hiddev_ioctl_string(hiddev, cmd, user_arg);
-               else
-                       r = -ENODEV;
-               mutex_unlock(&hiddev->existancelock);
-               return r;
+               r = hiddev_ioctl_string(hiddev, cmd, user_arg);
+               break;
 
        case HIDIOCINITREPORT:
-               mutex_lock(&hiddev->existancelock);
-               if (!hiddev->exist) {
-                       mutex_unlock(&hiddev->existancelock);
-                       return -ENODEV;
-               }
                usbhid_init_reports(hid);
-               mutex_unlock(&hiddev->existancelock);
-
-               return 0;
+               r = 0;
+               break;
 
        case HIDIOCGREPORT:
-               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
-                       return -EFAULT;
+               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+                       r = -EFAULT;
+                       break;
+               }
 
                if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
-                       return -EINVAL;
+                       break;
 
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       return -EINVAL;
+               report = hiddev_lookup_report(hid, &rinfo);
+               if (report == NULL)
+                       break;
 
-               mutex_lock(&hiddev->existancelock);
-               if (hiddev->exist) {
-                       usbhid_submit_report(hid, report, USB_DIR_IN);
-                       usbhid_wait_io(hid);
-               }
-               mutex_unlock(&hiddev->existancelock);
+               usbhid_submit_report(hid, report, USB_DIR_IN);
+               usbhid_wait_io(hid);
 
-               return 0;
+               r = 0;
+               break;
 
        case HIDIOCSREPORT:
-               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
-                       return -EFAULT;
+               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+                       r = -EFAULT;
+                       break;
+               }
 
                if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
-                       return -EINVAL;
+                       break;
 
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       return -EINVAL;
+               report = hiddev_lookup_report(hid, &rinfo);
+               if (report == NULL)
+                       break;
 
-               mutex_lock(&hiddev->existancelock);
-               if (hiddev->exist) {
-                       usbhid_submit_report(hid, report, USB_DIR_OUT);
-                       usbhid_wait_io(hid);
-               }
-               mutex_unlock(&hiddev->existancelock);
+               usbhid_submit_report(hid, report, USB_DIR_OUT);
+               usbhid_wait_io(hid);
 
-               return 0;
+               r = 0;
+               break;
 
        case HIDIOCGREPORTINFO:
-               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
-                       return -EFAULT;
+               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+                       r = -EFAULT;
+                       break;
+               }
 
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       return -EINVAL;
+               report = hiddev_lookup_report(hid, &rinfo);
+               if (report == NULL)
+                       break;
 
                rinfo.num_fields = report->maxfield;
 
-               if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
-                       return -EFAULT;
-
-               return 0;
+               r = copy_to_user(user_arg, &rinfo, sizeof(rinfo)) ?
+                       -EFAULT : 0;
+               break;
 
        case HIDIOCGFIELDINFO:
-               if (copy_from_user(&finfo, user_arg, sizeof(finfo)))
-                       return -EFAULT;
+               if (copy_from_user(&finfo, user_arg, sizeof(finfo))) {
+                       r = -EFAULT;
+                       break;
+               }
+
                rinfo.report_type = finfo.report_type;
                rinfo.report_id = finfo.report_id;
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       return -EINVAL;
+
+               report = hiddev_lookup_report(hid, &rinfo);
+               if (report == NULL)
+                       break;
 
                if (finfo.field_index >= report->maxfield)
-                       return -EINVAL;
+                       break;
 
                field = report->field[finfo.field_index];
                memset(&finfo, 0, sizeof(finfo));
@@ -760,10 +765,9 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                finfo.unit_exponent = field->unit_exponent;
                finfo.unit = field->unit;
 
-               if (copy_to_user(user_arg, &finfo, sizeof(finfo)))
-                       return -EFAULT;
-
-               return 0;
+               r = copy_to_user(user_arg, &finfo, sizeof(finfo)) ?
+                       -EFAULT : 0;
+               break;
 
        case HIDIOCGUCODE:
                /* fall through */
@@ -772,57 +776,66 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case HIDIOCGUSAGES:
        case HIDIOCSUSAGES:
        case HIDIOCGCOLLECTIONINDEX:
-               mutex_lock(&hiddev->existancelock);
-               if (hiddev->exist)
-                       r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
-               else
-                       r = -ENODEV;
-               mutex_unlock(&hiddev->existancelock);
-               return r;
+               r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
+               break;
 
        case HIDIOCGCOLLECTIONINFO:
-               if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
-                       return -EFAULT;
+               if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) {
+                       r = -EFAULT;
+                       break;
+               }
 
                if (cinfo.index >= hid->maxcollection)
-                       return -EINVAL;
+                       break;
 
                cinfo.type = hid->collection[cinfo.index].type;
                cinfo.usage = hid->collection[cinfo.index].usage;
                cinfo.level = hid->collection[cinfo.index].level;
 
-               if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))
-                       return -EFAULT;
-               return 0;
+               r = copy_to_user(user_arg, &cinfo, sizeof(cinfo)) ?
+                       -EFAULT : 0;
+               break;
 
        default:
-
                if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
-                       return -EINVAL;
+                       break;
 
                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
                        int len;
-                       if (!hid->name)
-                               return 0;
+
+                       if (!hid->name) {
+                               r = 0;
+                               break;
+                       }
+
                        len = strlen(hid->name) + 1;
                        if (len > _IOC_SIZE(cmd))
                                 len = _IOC_SIZE(cmd);
-                       return copy_to_user(user_arg, hid->name, len) ?
+                       r = copy_to_user(user_arg, hid->name, len) ?
                                -EFAULT : len;
+                       break;
                }
 
                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
                        int len;
-                       if (!hid->phys)
-                               return 0;
+
+                       if (!hid->phys) {
+                               r = 0;
+                               break;
+                       }
+
                        len = strlen(hid->phys) + 1;
                        if (len > _IOC_SIZE(cmd))
                                len = _IOC_SIZE(cmd);
-                       return copy_to_user(user_arg, hid->phys, len) ?
+                       r = copy_to_user(user_arg, hid->phys, len) ?
                                -EFAULT : len;
+                       break;
                }
        }
-       return -EINVAL;
+
+ret_unlock:
+       mutex_unlock(&hiddev->existancelock);
+       return r;
 }
 
 #ifdef CONFIG_COMPAT
@@ -892,7 +905,7 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
        hiddev->exist = 1;
        retval = usb_register_dev(usbhid->intf, &hiddev_class);
        if (retval) {
-               err_hid("Not able to get a minor for this device.");
+               hid_err(hid, "Not able to get a minor for this device\n");
                hid->hiddev = NULL;
                kfree(hiddev);
                return -1;
index 89d2e847dcc671b65f15484b3df34f6c4a6c288d..1673cac93d77bfa22aba124c0a17ce6cc5c05e56 100644 (file)
@@ -95,7 +95,6 @@ struct usbhid_device {
        unsigned long stop_retry;                                       /* Time to give up, in jiffies */
        unsigned int retry_delay;                                       /* Delay length in ms */
        struct work_struct reset_work;                                  /* Task context for resets */
-       struct work_struct restart_work;                                /* waking up for output to be done in a task */
        wait_queue_head_t wait;                                         /* For sleeping */
        int ledcount;                                                   /* counting the number of active leds */
 };
index a948605564fbd8ca63ceadfb2e6f2431678de433..065817329f03b68fe1e100a78559baddd568ce9e 100644 (file)
@@ -24,6 +24,8 @@
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -104,16 +106,18 @@ static void usb_kbd_irq(struct urb *urb)
                        if (usb_kbd_keycode[kbd->old[i]])
                                input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
                        else
-                               dev_info(&urb->dev->dev,
-                                               "Unknown key (scancode %#x) released.\n", kbd->old[i]);
+                               hid_info(urb->dev,
+                                        "Unknown key (scancode %#x) released.\n",
+                                        kbd->old[i]);
                }
 
                if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
                        if (usb_kbd_keycode[kbd->new[i]])
                                input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
                        else
-                               dev_info(&urb->dev->dev,
-                                               "Unknown key (scancode %#x) released.\n", kbd->new[i]);
+                               hid_info(urb->dev,
+                                        "Unknown key (scancode %#x) released.\n",
+                                        kbd->new[i]);
                }
        }
 
@@ -124,9 +128,9 @@ static void usb_kbd_irq(struct urb *urb)
 resubmit:
        i = usb_submit_urb (urb, GFP_ATOMIC);
        if (i)
-               err_hid ("can't resubmit intr, %s-%s/input0, status %d",
-                               kbd->usbdev->bus->bus_name,
-                               kbd->usbdev->devpath, i);
+               hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
+                       kbd->usbdev->bus->bus_name,
+                       kbd->usbdev->devpath, i);
 }
 
 static int usb_kbd_event(struct input_dev *dev, unsigned int type,
@@ -150,7 +154,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type,
        *(kbd->leds) = kbd->newleds;
        kbd->led->dev = kbd->usbdev;
        if (usb_submit_urb(kbd->led, GFP_ATOMIC))
-               err_hid("usb_submit_urb(leds) failed");
+               pr_err("usb_submit_urb(leds) failed\n");
 
        return 0;
 }
@@ -160,7 +164,7 @@ static void usb_kbd_led(struct urb *urb)
        struct usb_kbd *kbd = urb->context;
 
        if (urb->status)
-               dev_warn(&urb->dev->dev, "led urb status %d received\n",
+               hid_warn(urb->dev, "led urb status %d received\n",
                         urb->status);
 
        if (*(kbd->leds) == kbd->newleds)
@@ -169,7 +173,7 @@ static void usb_kbd_led(struct urb *urb)
        *(kbd->leds) = kbd->newleds;
        kbd->led->dev = kbd->usbdev;
        if (usb_submit_urb(kbd->led, GFP_ATOMIC))
-               err_hid("usb_submit_urb(leds) failed");
+               hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
 }
 
 static int usb_kbd_open(struct input_dev *dev)
index a56f6adf3b767b18fc664a2508f01caab5a135a2..bdc13d28b1ea2c09924f6b41f6c873807c49f1ab 100644 (file)
@@ -274,6 +274,16 @@ config SENSORS_ATXP1
          This driver can also be built as a module.  If so, the module
          will be called atxp1.
 
+config SENSORS_DS620
+       tristate "Dallas Semiconductor DS620"
+       depends on I2C
+       help
+         If you say yes here you get support for Dallas Semiconductor
+         DS620 sensor chip.
+
+         This driver can also be built as a module.  If so, the module
+         will be called ds620.
+
 config SENSORS_DS1621
        tristate "Dallas Semiconductor DS1621 and DS1625"
        depends on I2C
@@ -734,6 +744,16 @@ config SENSORS_SHT15
          This driver can also be built as a module.  If so, the module
          will be called sht15.
 
+config SENSORS_SHT21
+       tristate "Sensiron humidity and temperature sensors. SHT21 and compat."
+       depends on I2C
+       help
+         If you say yes here you get support for the Sensiron SHT21, SHT25
+         humidity and temperature sensors.
+
+         This driver can also be built as a module.  If so, the module
+         will be called sht21.
+
 config SENSORS_S3C
        tristate "Samsung built-in ADC"
        depends on S3C_ADC
index 2479b3da272cab19e943fb4a1f82515083f30029..dde02d99c2386aa81c4a96351e5dc7316d75d419 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_ATXP1)   += atxp1.o
 obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
 obj-$(CONFIG_SENSORS_PKGTEMP)  += pkgtemp.o
 obj-$(CONFIG_SENSORS_DME1737)  += dme1737.o
+obj-$(CONFIG_SENSORS_DS620)    += ds620.o
 obj-$(CONFIG_SENSORS_DS1621)   += ds1621.o
 obj-$(CONFIG_SENSORS_EMC1403)  += emc1403.o
 obj-$(CONFIG_SENSORS_EMC2103)  += emc2103.o
@@ -90,6 +91,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
 obj-$(CONFIG_SENSORS_PCF8591)  += pcf8591.o
 obj-$(CONFIG_SENSORS_S3C)      += s3c-hwmon.o
 obj-$(CONFIG_SENSORS_SHT15)    += sht15.o
+obj-$(CONFIG_SENSORS_SHT21)    += sht21.o
 obj-$(CONFIG_SENSORS_SIS5595)  += sis5595.o
 obj-$(CONFIG_SENSORS_SMM665)   += smm665.o
 obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
index 03694cc17a32e20e2d64b7f402b5fcaa9989e5fd..8f07a9dda15216073df1cd937f68d33787e71306 100644 (file)
@@ -20,6 +20,9 @@
     the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because
     of lack of specs the CPU/RAM voltage & frequency control is not supported!
 */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init.h>
@@ -220,6 +223,10 @@ struct abituguru_data {
        u8 pwm_settings[ABIT_UGURU_MAX_PWMS][5];
 };
 
+static const char *never_happen = "This should never happen.";
+static const char *report_this =
+       "Please report this to the abituguru maintainer (see MAINTAINERS)";
+
 /* wait till the uguru is in the specified state */
 static int abituguru_wait(struct abituguru_data *data, u8 state)
 {
@@ -438,8 +445,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
 
        /* Test val is sane / usable for sensor type detection. */
        if ((val < 10u) || (val > 250u)) {
-               printk(KERN_WARNING ABIT_UGURU_NAME
-                       ": bank1-sensor: %d reading (%d) too close to limits, "
+               pr_warn("bank1-sensor: %d reading (%d) too close to limits, "
                        "unable to determine sensor type, skipping sensor\n",
                        (int)sensor_addr, (int)val);
                /* assume no sensor is there for sensors for which we can't
@@ -535,10 +541,8 @@ abituguru_detect_bank1_sensor_type_exit:
                                3) == 3)
                        break;
        if (i == 3) {
-               printk(KERN_ERR ABIT_UGURU_NAME
-                       ": Fatal error could not restore original settings. "
-                       "This should never happen please report this to the "
-                       "abituguru maintainer (see MAINTAINERS)\n");
+               pr_err("Fatal error could not restore original settings. %s %s\n",
+                      never_happen, report_this);
                return -ENODEV;
        }
        return ret;
@@ -1268,14 +1272,12 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
        }
        /* Fail safe check, this should never happen! */
        if (sysfs_names_free < 0) {
-               printk(KERN_ERR ABIT_UGURU_NAME ": Fatal error ran out of "
-                      "space for sysfs attr names. This should never "
-                      "happen please report to the abituguru maintainer "
-                      "(see MAINTAINERS)\n");
+               pr_err("Fatal error ran out of space for sysfs attr names. %s %s",
+                      never_happen, report_this);
                res = -ENAMETOOLONG;
                goto abituguru_probe_error;
        }
-       printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n");
+       pr_info("found Abit uGuru\n");
 
        /* Register sysfs hooks */
        for (i = 0; i < sysfs_attr_i; i++)
@@ -1432,8 +1434,7 @@ static int __init abituguru_detect(void)
                "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
 
        if (force) {
-               printk(KERN_INFO ABIT_UGURU_NAME ": Assuming Abit uGuru is "
-                               "present because of \"force\" parameter\n");
+               pr_info("Assuming Abit uGuru is present because of \"force\" parameter\n");
                return ABIT_UGURU_BASE;
        }
 
@@ -1467,8 +1468,7 @@ static int __init abituguru_init(void)
 
        abituguru_pdev = platform_device_alloc(ABIT_UGURU_NAME, address);
        if (!abituguru_pdev) {
-               printk(KERN_ERR ABIT_UGURU_NAME
-                       ": Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                err = -ENOMEM;
                goto exit_driver_unregister;
        }
@@ -1479,15 +1479,13 @@ static int __init abituguru_init(void)
 
        err = platform_device_add_resources(abituguru_pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR ABIT_UGURU_NAME
-                       ": Device resource addition failed (%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
        err = platform_device_add(abituguru_pdev);
        if (err) {
-               printk(KERN_ERR ABIT_UGURU_NAME
-                       ": Device addition failed (%d)\n", err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
index 3cf28af614b55cd894e7318c73b5d21ec3a27e27..48d21e22e9302a66e2d8b467ea5c42532875514e 100644 (file)
@@ -23,6 +23,9 @@
     chip found on newer Abit uGuru motherboards. Note: because of lack of specs
     only reading the sensors and their settings is supported.
 */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -608,6 +611,9 @@ static int verbose = 1;
 module_param(verbose, bool, 0644);
 MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting");
 
+static const char *never_happen = "This should never happen.";
+static const char *report_this =
+       "Please report this to the abituguru3 maintainer (see MAINTAINERS)";
 
 /* wait while the uguru is busy (usually after a write) */
 static int abituguru3_wait_while_busy(struct abituguru3_data *data)
@@ -940,15 +946,13 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
                if (abituguru3_motherboards[i].id == id)
                        break;
        if (!abituguru3_motherboards[i].id) {
-               printk(KERN_ERR ABIT_UGURU3_NAME ": error unknown motherboard "
-                       "ID: %04X. Please report this to the abituguru3 "
-                       "maintainer (see MAINTAINERS)\n", (unsigned int)id);
+               pr_err("error unknown motherboard ID: %04X. %s\n",
+                      (unsigned int)id, report_this);
                goto abituguru3_probe_error;
        }
        data->sensors = abituguru3_motherboards[i].sensors;
 
-       printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard "
-               "ID: %04X\n", (unsigned int)id);
+       pr_info("found Abit uGuru3, motherboard ID: %04X\n", (unsigned int)id);
 
        /* Fill the sysfs attr array */
        sysfs_attr_i = 0;
@@ -957,11 +961,8 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
        for (i = 0; data->sensors[i].name; i++) {
                /* Fail safe check, this should never happen! */
                if (i >= ABIT_UGURU3_MAX_NO_SENSORS) {
-                       printk(KERN_ERR ABIT_UGURU3_NAME
-                               ": Fatal error motherboard has more sensors "
-                               "then ABIT_UGURU3_MAX_NO_SENSORS. This should "
-                               "never happen please report to the abituguru3 "
-                               "maintainer (see MAINTAINERS)\n");
+                       pr_err("Fatal error motherboard has more sensors then ABIT_UGURU3_MAX_NO_SENSORS. %s %s\n",
+                              never_happen, report_this);
                        res = -ENAMETOOLONG;
                        goto abituguru3_probe_error;
                }
@@ -983,10 +984,8 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
        }
        /* Fail safe check, this should never happen! */
        if (sysfs_names_free < 0) {
-               printk(KERN_ERR ABIT_UGURU3_NAME
-                       ": Fatal error ran out of space for sysfs attr names. "
-                       "This should never happen please report to the "
-                       "abituguru3 maintainer (see MAINTAINERS)\n");
+               pr_err("Fatal error ran out of space for sysfs attr names. %s %s\n",
+                      never_happen, report_this);
                res = -ENAMETOOLONG;
                goto abituguru3_probe_error;
        }
@@ -1189,8 +1188,7 @@ static int __init abituguru3_detect(void)
                "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
 
        if (force) {
-               printk(KERN_INFO ABIT_UGURU3_NAME ": Assuming Abit uGuru3 is "
-                               "present because of \"force\" parameter\n");
+               pr_info("Assuming Abit uGuru3 is present because of \"force\" parameter\n");
                return 0;
        }
 
@@ -1219,10 +1217,8 @@ static int __init abituguru3_init(void)
                        return err;
 
 #ifdef CONFIG_DMI
-               printk(KERN_WARNING ABIT_UGURU3_NAME ": this motherboard was "
-                       "not detected using DMI. Please send the output of "
-                       "\"dmidecode\" to the abituguru3 maintainer "
-                       "(see MAINTAINERS)\n");
+               pr_warn("this motherboard was not detected using DMI. "
+                       "Please send the output of \"dmidecode\" to the abituguru3 maintainer (see MAINTAINERS)\n");
 #endif
        }
 
@@ -1233,8 +1229,7 @@ static int __init abituguru3_init(void)
        abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME,
                                                ABIT_UGURU3_BASE);
        if (!abituguru3_pdev) {
-               printk(KERN_ERR ABIT_UGURU3_NAME
-                       ": Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                err = -ENOMEM;
                goto exit_driver_unregister;
        }
@@ -1245,15 +1240,13 @@ static int __init abituguru3_init(void)
 
        err = platform_device_add_resources(abituguru3_pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR ABIT_UGURU3_NAME
-                       ": Device resource addition failed (%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
        err = platform_device_add(abituguru3_pdev);
        if (err) {
-               printk(KERN_ERR ABIT_UGURU3_NAME
-                       ": Device addition failed (%d)\n", err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
index 87d92a56a939fcc531c934a1dd70f6ab6f83ab0c..c6d1ce059aeabb80e486c4bdb84f5d7ff57279e5 100644 (file)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
@@ -274,7 +276,7 @@ static int adt7470_read_temperatures(struct i2c_client *client,
        i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
 
        if (res) {
-               printk(KERN_ERR "ha ha, interrupted");
+               pr_err("ha ha, interrupted\n");
                return -EAGAIN;
        }
 
index b6598aa557a0dcfe56fb87902319dff2394b6934..ce0372f0615ebd37474a1ab9e93ecc3a3d40e79f 100644 (file)
@@ -4,6 +4,7 @@
  * computers.
  *
  * Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
+ * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
  *
  * Based on hdaps.c driver:
  * Copyright (C) 2005 Robert Love <rml@novell.com>
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/input-polldev.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/timer.h>
 #include <linux/dmi.h>
@@ -49,6 +53,7 @@
 
 #define APPLESMC_MAX_DATA_LENGTH 32
 
+/* wait up to 32 ms for a status change. */
 #define APPLESMC_MIN_WAIT      0x0040
 #define APPLESMC_MAX_WAIT      0x8000
 
 
 #define FANS_COUNT             "FNum" /* r-o ui8 */
 #define FANS_MANUAL            "FS! " /* r-w ui16 */
-#define FAN_ACTUAL_SPEED       "F0Ac" /* r-o fpe2 (2 bytes) */
-#define FAN_MIN_SPEED          "F0Mn" /* r-o fpe2 (2 bytes) */
-#define FAN_MAX_SPEED          "F0Mx" /* r-o fpe2 (2 bytes) */
-#define FAN_SAFE_SPEED         "F0Sf" /* r-o fpe2 (2 bytes) */
-#define FAN_TARGET_SPEED       "F0Tg" /* r-w fpe2 (2 bytes) */
-#define FAN_POSITION           "F0ID" /* r-o char[16] */
-
-/*
- * Temperature sensors keys (sp78 - 2 bytes).
- */
-static const char *temperature_sensors_sets[][41] = {
-/* Set 0: Macbook Pro */
-       { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
-         "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
-/* Set 1: Macbook2 set */
-       { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "TTF0", "Th0H",
-         "Th0S", "Th1H", NULL },
-/* Set 2: Macbook set */
-       { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
-         "Th1H", "Ts0P", NULL },
-/* Set 3: Macmini set */
-       { "TC0D", "TC0P", NULL },
-/* Set 4: Mac Pro (2 x Quad-Core) */
-       { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
-         "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P",
-         "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S",
-         "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P",
-         "TM9S", "TN0H", "TS0C", NULL },
-/* Set 5: iMac */
-       { "TC0D", "TA0P", "TG0P", "TG0D", "TG0H", "TH0P", "Tm0P", "TO0P",
-         "Tp0C", NULL },
-/* Set 6: Macbook3 set */
-       { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H",
-         "Th0S", "Th1H", NULL },
-/* Set 7: Macbook Air */
-       { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP",
-         "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL },
-/* Set 8: Macbook Pro 4,1 (Penryn) */
-       { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H",
-         "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
-/* Set 9: Macbook Pro 3,1 (Santa Rosa) */
-       { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P",
-         "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
-/* Set 10: iMac 5,1 */
-       { "TA0P", "TC0D", "TC0P", "TG0D", "TH0P", "TO0P", "Tm0P", NULL },
-/* Set 11: Macbook 5,1 */
-       { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0P", "TN0D", "TN0P",
-         "TTF0", "Th0H", "Th1H", "ThFH", "Ts0P", "Ts0S", NULL },
-/* Set 12: Macbook Pro 5,1 */
-       { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
-         "TG0F", "TG0H", "TG0P", "TG0T", "TG1H", "TN0D", "TN0P", "TTF0",
-         "Th2H", "Tm0P", "Ts0P", "Ts0S", NULL },
-/* Set 13: iMac 8,1 */
-       { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
-         "TL0P", "TO0P", "TW0P", "Tm0P", "Tp0P", NULL },
-/* Set 14: iMac 6,1 */
-       { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
-         "TO0P", "Tp0P", NULL },
-/* Set 15: MacBook Air 2,1 */
-       { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0",
-         "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P",
-         "Ts0S", NULL },
-/* Set 16: Mac Pro 3,1 (2 x Quad-Core) */
-       { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
-         "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "TH0P", "TH1P",
-         "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S", "TM1P",
-         "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", "TM9S",
-         "TN0C", "TN0D", "TN0H", "TS0C", "Tp0C", "Tp1C", "Tv0S", "Tv1S",
-         NULL },
-/* Set 17: iMac 9,1 */
-       { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TH0P", "TL0P",
-         "TN0D", "TN0H", "TN0P", "TO0P", "Tm0P", "Tp0P", NULL },
-/* Set 18: MacBook Pro 2,2 */
-       { "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0",
-         "Th0H", "Th1H", "Tm0P", "Ts0P", NULL },
-/* Set 19: Macbook Pro 5,3 */
-       { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
-         "TG0F", "TG0H", "TG0P", "TG0T", "TN0D", "TN0P", "TTF0", "Th2H",
-         "Tm0P", "Ts0P", "Ts0S", NULL },
-/* Set 20: MacBook Pro 5,4 */
-       { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TN0D",
-         "TN0P", "TTF0", "Th2H", "Ts0P", "Ts0S", NULL },
-/* Set 21: MacBook Pro 6,2 */
-       { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", "TC0P", "TC1C", "TG0D",
-         "TG0P", "TG0T", "TMCD", "TP0P", "TPCD", "Th1H", "Th2H", "Tm0P",
-         "Ts0P", "Ts0S", NULL },
-/* Set 22: MacBook Pro 7,1 */
-       { "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", "TN0D", "TN0P", "TN0S",
-         "TN1D", "TN1F", "TN1G", "TN1S", "Th1H", "Ts0P", "Ts0S", NULL },
-};
+#define FAN_ID_FMT             "F%dID" /* r-o char[16] */
 
 /* List of keys used to read/write fan speeds */
-static const char* fan_speed_keys[] = {
-       FAN_ACTUAL_SPEED,
-       FAN_MIN_SPEED,
-       FAN_MAX_SPEED,
-       FAN_SAFE_SPEED,
-       FAN_TARGET_SPEED
+static const char *const fan_speed_fmt[] = {
+       "F%dAc",                /* actual speed */
+       "F%dMn",                /* minimum speed (rw) */
+       "F%dMx",                /* maximum speed */
+       "F%dSf",                /* safe speed - not all models */
+       "F%dTg",                /* target speed (manual: rw) */
 };
 
 #define INIT_TIMEOUT_MSECS     5000    /* wait up to 5s for device init ... */
@@ -184,14 +100,48 @@ static const char* fan_speed_keys[] = {
 #define SENSOR_Y 1
 #define SENSOR_Z 2
 
-/* Structure to be passed to DMI_MATCH function */
-struct dmi_match_data {
-/* Indicates whether this computer has an accelerometer. */
-       int accelerometer;
-/* Indicates whether this computer has light sensors and keyboard backlight. */
-       int light;
-/* Indicates which temperature sensors set to use. */
-       int temperature_set;
+#define to_index(attr) (to_sensor_dev_attr(attr)->index & 0xffff)
+#define to_option(attr) (to_sensor_dev_attr(attr)->index >> 16)
+
+/* Dynamic device node attributes */
+struct applesmc_dev_attr {
+       struct sensor_device_attribute sda;     /* hwmon attributes */
+       char name[32];                          /* room for node file name */
+};
+
+/* Dynamic device node group */
+struct applesmc_node_group {
+       char *format;                           /* format string */
+       void *show;                             /* show function */
+       void *store;                            /* store function */
+       int option;                             /* function argument */
+       struct applesmc_dev_attr *nodes;        /* dynamic node array */
+};
+
+/* AppleSMC entry - cached register information */
+struct applesmc_entry {
+       char key[5];            /* four-letter key code */
+       u8 valid;               /* set when entry is successfully read once */
+       u8 len;                 /* bounded by APPLESMC_MAX_DATA_LENGTH */
+       char type[5];           /* four-letter type code */
+       u8 flags;               /* 0x10: func; 0x40: write; 0x80: read */
+};
+
+/* Register lookup and registers common to all SMCs */
+static struct applesmc_registers {
+       struct mutex mutex;             /* register read/write mutex */
+       unsigned int key_count;         /* number of SMC registers */
+       unsigned int fan_count;         /* number of fans */
+       unsigned int temp_count;        /* number of temperature registers */
+       unsigned int temp_begin;        /* temperature lower index bound */
+       unsigned int temp_end;          /* temperature upper index bound */
+       int num_light_sensors;          /* number of light sensors */
+       bool has_accelerometer;         /* has motion sensor */
+       bool has_key_backlight;         /* has keyboard backlight */
+       bool init_complete;             /* true when fully initialized */
+       struct applesmc_entry *cache;   /* cached key entries */
+} smcreg = {
+       .mutex = __MUTEX_INITIALIZER(smcreg.mutex),
 };
 
 static const int debug;
@@ -203,20 +153,6 @@ static u8 backlight_state[2];
 static struct device *hwmon_dev;
 static struct input_polled_dev *applesmc_idev;
 
-/* Indicates whether this computer has an accelerometer. */
-static unsigned int applesmc_accelerometer;
-
-/* Indicates whether this computer has light sensors and keyboard backlight. */
-static unsigned int applesmc_light;
-
-/* The number of fans handled by the driver */
-static unsigned int fans_handled;
-
-/* Indicates which temperature sensors set to use. */
-static unsigned int applesmc_temperature_set;
-
-static DEFINE_MUTEX(applesmc_lock);
-
 /*
  * Last index written to key_at_index sysfs file, and value to use for all other
  * key_at_index_* sysfs files.
@@ -238,18 +174,10 @@ static int __wait_status(u8 val)
 
        for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
                udelay(us);
-               if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
-                       if (debug)
-                               printk(KERN_DEBUG
-                                       "Waited %d us for status %x\n",
-                                       2 * us - APPLESMC_MIN_WAIT, val);
+               if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val)
                        return 0;
-               }
        }
 
-       printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
-                                               val, inb(APPLESMC_CMD_PORT));
-
        return -EIO;
 }
 
@@ -267,159 +195,242 @@ static int send_command(u8 cmd)
                if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
                        return 0;
        }
-       printk(KERN_WARNING "applesmc: command failed: %x -> %x\n",
-               cmd, inb(APPLESMC_CMD_PORT));
        return -EIO;
 }
 
-/*
- * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
- * Returns zero on success or a negative error on failure. Callers must
- * hold applesmc_lock.
- */
-static int applesmc_read_key(const char* key, u8* buffer, u8 len)
+static int send_argument(const char *key)
 {
        int i;
 
-       if (len > APPLESMC_MAX_DATA_LENGTH) {
-               printk(KERN_ERR "applesmc_read_key: cannot read more than "
-                                       "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
-               return -EINVAL;
-       }
-
-       if (send_command(APPLESMC_READ_CMD))
-               return -EIO;
-
        for (i = 0; i < 4; i++) {
                outb(key[i], APPLESMC_DATA_PORT);
                if (__wait_status(0x04))
                        return -EIO;
        }
-       if (debug)
-               printk(KERN_DEBUG "<%s", key);
+       return 0;
+}
+
+static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
+{
+       int i;
+
+       if (send_command(cmd) || send_argument(key)) {
+               pr_warn("%s: read arg fail\n", key);
+               return -EIO;
+       }
 
        outb(len, APPLESMC_DATA_PORT);
-       if (debug)
-               printk(KERN_DEBUG ">%x", len);
 
        for (i = 0; i < len; i++) {
-               if (__wait_status(0x05))
+               if (__wait_status(0x05)) {
+                       pr_warn("%s: read data fail\n", key);
                        return -EIO;
+               }
                buffer[i] = inb(APPLESMC_DATA_PORT);
-               if (debug)
-                       printk(KERN_DEBUG "<%x", buffer[i]);
        }
-       if (debug)
-               printk(KERN_DEBUG "\n");
 
        return 0;
 }
 
-/*
- * applesmc_write_key - writes len bytes from buffer to a given key.
- * Returns zero on success or a negative error on failure. Callers must
- * hold applesmc_lock.
- */
-static int applesmc_write_key(const char* key, u8* buffer, u8 len)
+static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
 {
        int i;
 
-       if (len > APPLESMC_MAX_DATA_LENGTH) {
-               printk(KERN_ERR "applesmc_write_key: cannot write more than "
-                                       "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
-               return -EINVAL;
-       }
-
-       if (send_command(APPLESMC_WRITE_CMD))
+       if (send_command(cmd) || send_argument(key)) {
+               pr_warn("%s: write arg fail\n", key);
                return -EIO;
-
-       for (i = 0; i < 4; i++) {
-               outb(key[i], APPLESMC_DATA_PORT);
-               if (__wait_status(0x04))
-                       return -EIO;
        }
 
        outb(len, APPLESMC_DATA_PORT);
 
        for (i = 0; i < len; i++) {
-               if (__wait_status(0x04))
+               if (__wait_status(0x04)) {
+                       pr_warn("%s: write data fail\n", key);
                        return -EIO;
+               }
                outb(buffer[i], APPLESMC_DATA_PORT);
        }
 
        return 0;
 }
 
+static int read_register_count(unsigned int *count)
+{
+       __be32 be;
+       int ret;
+
+       ret = read_smc(APPLESMC_READ_CMD, KEY_COUNT_KEY, (u8 *)&be, 4);
+       if (ret)
+               return ret;
+
+       *count = be32_to_cpu(be);
+       return 0;
+}
+
 /*
- * applesmc_get_key_at_index - get key at index, and put the result in key
- * (char[6]). Returns zero on success or a negative error on failure. Callers
- * must hold applesmc_lock.
+ * Serialized I/O
+ *
+ * Returns zero on success or a negative error on failure.
+ * All functions below are concurrency safe - callers should NOT hold lock.
  */
-static int applesmc_get_key_at_index(int index, char* key)
+
+static int applesmc_read_entry(const struct applesmc_entry *entry,
+                              u8 *buf, u8 len)
 {
-       int i;
-       u8 readkey[4];
-       readkey[0] = index >> 24;
-       readkey[1] = index >> 16;
-       readkey[2] = index >> 8;
-       readkey[3] = index;
+       int ret;
 
-       if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD))
-               return -EIO;
+       if (entry->len != len)
+               return -EINVAL;
+       mutex_lock(&smcreg.mutex);
+       ret = read_smc(APPLESMC_READ_CMD, entry->key, buf, len);
+       mutex_unlock(&smcreg.mutex);
 
-       for (i = 0; i < 4; i++) {
-               outb(readkey[i], APPLESMC_DATA_PORT);
-               if (__wait_status(0x04))
-                       return -EIO;
+       return ret;
+}
+
+static int applesmc_write_entry(const struct applesmc_entry *entry,
+                               const u8 *buf, u8 len)
+{
+       int ret;
+
+       if (entry->len != len)
+               return -EINVAL;
+       mutex_lock(&smcreg.mutex);
+       ret = write_smc(APPLESMC_WRITE_CMD, entry->key, buf, len);
+       mutex_unlock(&smcreg.mutex);
+       return ret;
+}
+
+static const struct applesmc_entry *applesmc_get_entry_by_index(int index)
+{
+       struct applesmc_entry *cache = &smcreg.cache[index];
+       u8 key[4], info[6];
+       __be32 be;
+       int ret = 0;
+
+       if (cache->valid)
+               return cache;
+
+       mutex_lock(&smcreg.mutex);
+
+       if (cache->valid)
+               goto out;
+       be = cpu_to_be32(index);
+       ret = read_smc(APPLESMC_GET_KEY_BY_INDEX_CMD, (u8 *)&be, key, 4);
+       if (ret)
+               goto out;
+       ret = read_smc(APPLESMC_GET_KEY_TYPE_CMD, key, info, 6);
+       if (ret)
+               goto out;
+
+       memcpy(cache->key, key, 4);
+       cache->len = info[0];
+       memcpy(cache->type, &info[1], 4);
+       cache->flags = info[5];
+       cache->valid = 1;
+
+out:
+       mutex_unlock(&smcreg.mutex);
+       if (ret)
+               return ERR_PTR(ret);
+       return cache;
+}
+
+static int applesmc_get_lower_bound(unsigned int *lo, const char *key)
+{
+       int begin = 0, end = smcreg.key_count;
+       const struct applesmc_entry *entry;
+
+       while (begin != end) {
+               int middle = begin + (end - begin) / 2;
+               entry = applesmc_get_entry_by_index(middle);
+               if (IS_ERR(entry))
+                       return PTR_ERR(entry);
+               if (strcmp(entry->key, key) < 0)
+                       begin = middle + 1;
+               else
+                       end = middle;
        }
 
-       outb(4, APPLESMC_DATA_PORT);
+       *lo = begin;
+       return 0;
+}
 
-       for (i = 0; i < 4; i++) {
-               if (__wait_status(0x05))
-                       return -EIO;
-               key[i] = inb(APPLESMC_DATA_PORT);
+static int applesmc_get_upper_bound(unsigned int *hi, const char *key)
+{
+       int begin = 0, end = smcreg.key_count;
+       const struct applesmc_entry *entry;
+
+       while (begin != end) {
+               int middle = begin + (end - begin) / 2;
+               entry = applesmc_get_entry_by_index(middle);
+               if (IS_ERR(entry))
+                       return PTR_ERR(entry);
+               if (strcmp(key, entry->key) < 0)
+                       end = middle;
+               else
+                       begin = middle + 1;
        }
-       key[4] = 0;
 
+       *hi = begin;
        return 0;
 }
 
-/*
- * applesmc_get_key_type - get key type, and put the result in type (char[6]).
- * Returns zero on success or a negative error on failure. Callers must
- * hold applesmc_lock.
- */
-static int applesmc_get_key_type(char* key, char* type)
+static const struct applesmc_entry *applesmc_get_entry_by_key(const char *key)
 {
-       int i;
+       int begin, end;
+       int ret;
 
-       if (send_command(APPLESMC_GET_KEY_TYPE_CMD))
-               return -EIO;
+       ret = applesmc_get_lower_bound(&begin, key);
+       if (ret)
+               return ERR_PTR(ret);
+       ret = applesmc_get_upper_bound(&end, key);
+       if (ret)
+               return ERR_PTR(ret);
+       if (end - begin != 1)
+               return ERR_PTR(-EINVAL);
 
-       for (i = 0; i < 4; i++) {
-               outb(key[i], APPLESMC_DATA_PORT);
-               if (__wait_status(0x04))
-                       return -EIO;
-       }
+       return applesmc_get_entry_by_index(begin);
+}
 
-       outb(6, APPLESMC_DATA_PORT);
+static int applesmc_read_key(const char *key, u8 *buffer, u8 len)
+{
+       const struct applesmc_entry *entry;
 
-       for (i = 0; i < 6; i++) {
-               if (__wait_status(0x05))
-                       return -EIO;
-               type[i] = inb(APPLESMC_DATA_PORT);
-       }
-       type[5] = 0;
+       entry = applesmc_get_entry_by_key(key);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
+
+       return applesmc_read_entry(entry, buffer, len);
+}
+
+static int applesmc_write_key(const char *key, const u8 *buffer, u8 len)
+{
+       const struct applesmc_entry *entry;
 
+       entry = applesmc_get_entry_by_key(key);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
+
+       return applesmc_write_entry(entry, buffer, len);
+}
+
+static int applesmc_has_key(const char *key, bool *value)
+{
+       const struct applesmc_entry *entry;
+
+       entry = applesmc_get_entry_by_key(key);
+       if (IS_ERR(entry) && PTR_ERR(entry) != -EINVAL)
+               return PTR_ERR(entry);
+
+       *value = !IS_ERR(entry);
        return 0;
 }
 
 /*
- * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
- * hold applesmc_lock.
+ * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z).
  */
-static int applesmc_read_motion_sensor(int index, s16value)
+static int applesmc_read_motion_sensor(int index, s16 *value)
 {
        u8 buffer[2];
        int ret;
@@ -444,69 +455,120 @@ static int applesmc_read_motion_sensor(int index, s16* value)
 }
 
 /*
- * applesmc_device_init - initialize the accelerometer.  Returns zero on success
- * and negative error code on failure.  Can sleep.
+ * applesmc_device_init - initialize the accelerometer.  Can sleep.
  */
-static int applesmc_device_init(void)
+static void applesmc_device_init(void)
 {
-       int total, ret = -ENXIO;
+       int total;
        u8 buffer[2];
 
-       if (!applesmc_accelerometer)
-               return 0;
-
-       mutex_lock(&applesmc_lock);
+       if (!smcreg.has_accelerometer)
+               return;
 
        for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
-               if (debug)
-                       printk(KERN_DEBUG "applesmc try %d\n", total);
                if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
-                               (buffer[0] != 0x00 || buffer[1] != 0x00)) {
-                       if (total == INIT_TIMEOUT_MSECS) {
-                               printk(KERN_DEBUG "applesmc: device has"
-                                               " already been initialized"
-                                               " (0x%02x, 0x%02x).\n",
-                                               buffer[0], buffer[1]);
-                       } else {
-                               printk(KERN_DEBUG "applesmc: device"
-                                               " successfully initialized"
-                                               " (0x%02x, 0x%02x).\n",
-                                               buffer[0], buffer[1]);
-                       }
-                       ret = 0;
-                       goto out;
-               }
+                               (buffer[0] != 0x00 || buffer[1] != 0x00))
+                       return;
                buffer[0] = 0xe0;
                buffer[1] = 0x00;
                applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
                msleep(INIT_WAIT_MSECS);
        }
 
-       printk(KERN_WARNING "applesmc: failed to init the device\n");
-
-out:
-       mutex_unlock(&applesmc_lock);
-       return ret;
+       pr_warn("failed to init the device\n");
 }
 
 /*
- * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
- * applesmc_lock.
+ * applesmc_init_smcreg_try - Try to initialize register cache. Idempotent.
  */
-static int applesmc_get_fan_count(void)
+static int applesmc_init_smcreg_try(void)
 {
+       struct applesmc_registers *s = &smcreg;
+       bool left_light_sensor, right_light_sensor;
+       u8 tmp[1];
        int ret;
-       u8 buffer[1];
 
-       mutex_lock(&applesmc_lock);
+       if (s->init_complete)
+               return 0;
 
-       ret = applesmc_read_key(FANS_COUNT, buffer, 1);
+       ret = read_register_count(&s->key_count);
+       if (ret)
+               return ret;
+
+       if (!s->cache)
+               s->cache = kcalloc(s->key_count, sizeof(*s->cache), GFP_KERNEL);
+       if (!s->cache)
+               return -ENOMEM;
 
-       mutex_unlock(&applesmc_lock);
+       ret = applesmc_read_key(FANS_COUNT, tmp, 1);
        if (ret)
                return ret;
-       else
-               return buffer[0];
+       s->fan_count = tmp[0];
+
+       ret = applesmc_get_lower_bound(&s->temp_begin, "T");
+       if (ret)
+               return ret;
+       ret = applesmc_get_lower_bound(&s->temp_end, "U");
+       if (ret)
+               return ret;
+       s->temp_count = s->temp_end - s->temp_begin;
+
+       ret = applesmc_has_key(LIGHT_SENSOR_LEFT_KEY, &left_light_sensor);
+       if (ret)
+               return ret;
+       ret = applesmc_has_key(LIGHT_SENSOR_RIGHT_KEY, &right_light_sensor);
+       if (ret)
+               return ret;
+       ret = applesmc_has_key(MOTION_SENSOR_KEY, &s->has_accelerometer);
+       if (ret)
+               return ret;
+       ret = applesmc_has_key(BACKLIGHT_KEY, &s->has_key_backlight);
+       if (ret)
+               return ret;
+
+       s->num_light_sensors = left_light_sensor + right_light_sensor;
+       s->init_complete = true;
+
+       pr_info("key=%d fan=%d temp=%d acc=%d lux=%d kbd=%d\n",
+              s->key_count, s->fan_count, s->temp_count,
+              s->has_accelerometer,
+              s->num_light_sensors,
+              s->has_key_backlight);
+
+       return 0;
+}
+
+/*
+ * applesmc_init_smcreg - Initialize register cache.
+ *
+ * Retries until initialization is successful, or the operation times out.
+ *
+ */
+static int applesmc_init_smcreg(void)
+{
+       int ms, ret;
+
+       for (ms = 0; ms < INIT_TIMEOUT_MSECS; ms += INIT_WAIT_MSECS) {
+               ret = applesmc_init_smcreg_try();
+               if (!ret) {
+                       if (ms)
+                               pr_info("init_smcreg() took %d ms\n", ms);
+                       return 0;
+               }
+               msleep(INIT_WAIT_MSECS);
+       }
+
+       kfree(smcreg.cache);
+       smcreg.cache = NULL;
+
+       return ret;
+}
+
+static void applesmc_destroy_smcreg(void)
+{
+       kfree(smcreg.cache);
+       smcreg.cache = NULL;
+       smcreg.init_complete = false;
 }
 
 /* Device model stuff */
@@ -514,30 +576,27 @@ static int applesmc_probe(struct platform_device *dev)
 {
        int ret;
 
-       ret = applesmc_device_init();
+       ret = applesmc_init_smcreg();
        if (ret)
                return ret;
 
-       printk(KERN_INFO "applesmc: device successfully initialized.\n");
+       applesmc_device_init();
+
        return 0;
 }
 
 /* Synchronize device with memorized backlight state */
 static int applesmc_pm_resume(struct device *dev)
 {
-       mutex_lock(&applesmc_lock);
-       if (applesmc_light)
+       if (smcreg.has_key_backlight)
                applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
-       mutex_unlock(&applesmc_lock);
        return 0;
 }
 
 /* Reinitialize device on resume from hibernation */
 static int applesmc_pm_restore(struct device *dev)
 {
-       int ret = applesmc_device_init();
-       if (ret)
-               return ret;
+       applesmc_device_init();
        return applesmc_pm_resume(dev);
 }
 
@@ -571,20 +630,15 @@ static void applesmc_idev_poll(struct input_polled_dev *dev)
        struct input_dev *idev = dev->input;
        s16 x, y;
 
-       mutex_lock(&applesmc_lock);
-
        if (applesmc_read_motion_sensor(SENSOR_X, &x))
-               goto out;
+               return;
        if (applesmc_read_motion_sensor(SENSOR_Y, &y))
-               goto out;
+               return;
 
        x = -x;
        input_report_abs(idev, ABS_X, x - rest_x);
        input_report_abs(idev, ABS_Y, y - rest_y);
        input_sync(idev);
-
-out:
-       mutex_unlock(&applesmc_lock);
 }
 
 /* Sysfs Files */
@@ -601,8 +655,6 @@ static ssize_t applesmc_position_show(struct device *dev,
        int ret;
        s16 x, y, z;
 
-       mutex_lock(&applesmc_lock);
-
        ret = applesmc_read_motion_sensor(SENSOR_X, &x);
        if (ret)
                goto out;
@@ -614,7 +666,6 @@ static ssize_t applesmc_position_show(struct device *dev,
                goto out;
 
 out:
-       mutex_unlock(&applesmc_lock);
        if (ret)
                return ret;
        else
@@ -624,20 +675,20 @@ out:
 static ssize_t applesmc_light_show(struct device *dev,
                                struct device_attribute *attr, char *sysfsbuf)
 {
+       const struct applesmc_entry *entry;
        static int data_length;
        int ret;
        u8 left = 0, right = 0;
-       u8 buffer[10], query[6];
-
-       mutex_lock(&applesmc_lock);
+       u8 buffer[10];
 
        if (!data_length) {
-               ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
-               if (ret)
-                       goto out;
-               data_length = clamp_val(query[0], 0, 10);
-               printk(KERN_INFO "applesmc: light sensor data length set to "
-                       "%d\n", data_length);
+               entry = applesmc_get_entry_by_key(LIGHT_SENSOR_LEFT_KEY);
+               if (IS_ERR(entry))
+                       return PTR_ERR(entry);
+               if (entry->len > 10)
+                       return -ENXIO;
+               data_length = entry->len;
+               pr_info("light sensor data length set to %d\n", data_length);
        }
 
        ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
@@ -653,7 +704,6 @@ static ssize_t applesmc_light_show(struct device *dev,
        right = buffer[2];
 
 out:
-       mutex_unlock(&applesmc_lock);
        if (ret)
                return ret;
        else
@@ -664,36 +714,44 @@ out:
 static ssize_t applesmc_show_sensor_label(struct device *dev,
                        struct device_attribute *devattr, char *sysfsbuf)
 {
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       const char *key =
-               temperature_sensors_sets[applesmc_temperature_set][attr->index];
+       int index = smcreg.temp_begin + to_index(devattr);
+       const struct applesmc_entry *entry;
+
+       entry = applesmc_get_entry_by_index(index);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
 
-       return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
+       return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key);
 }
 
 /* Displays degree Celsius * 1000 */
 static ssize_t applesmc_show_temperature(struct device *dev,
                        struct device_attribute *devattr, char *sysfsbuf)
 {
+       int index = smcreg.temp_begin + to_index(devattr);
+       const struct applesmc_entry *entry;
        int ret;
        u8 buffer[2];
        unsigned int temp;
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       const char* key =
-               temperature_sensors_sets[applesmc_temperature_set][attr->index];
-
-       mutex_lock(&applesmc_lock);
 
-       ret = applesmc_read_key(key, buffer, 2);
-       temp = buffer[0]*1000;
-       temp += (buffer[1] >> 6) * 250;
-
-       mutex_unlock(&applesmc_lock);
+       entry = applesmc_get_entry_by_index(index);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
+       if (entry->len > 2)
+               return -EINVAL;
 
+       ret = applesmc_read_entry(entry, buffer, entry->len);
        if (ret)
                return ret;
-       else
-               return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
+
+       if (entry->len == 2) {
+               temp = buffer[0] * 1000;
+               temp += (buffer[1] >> 6) * 250;
+       } else {
+               temp = buffer[0] * 4000;
+       }
+
+       return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
 }
 
 static ssize_t applesmc_show_fan_speed(struct device *dev,
@@ -703,21 +761,12 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
        unsigned int speed = 0;
        char newkey[5];
        u8 buffer[2];
-       struct sensor_device_attribute_2 *sensor_attr =
-                                               to_sensor_dev_attr_2(attr);
-
-       newkey[0] = fan_speed_keys[sensor_attr->nr][0];
-       newkey[1] = '0' + sensor_attr->index;
-       newkey[2] = fan_speed_keys[sensor_attr->nr][2];
-       newkey[3] = fan_speed_keys[sensor_attr->nr][3];
-       newkey[4] = 0;
 
-       mutex_lock(&applesmc_lock);
+       sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
 
        ret = applesmc_read_key(newkey, buffer, 2);
        speed = ((buffer[0] << 8 | buffer[1]) >> 2);
 
-       mutex_unlock(&applesmc_lock);
        if (ret)
                return ret;
        else
@@ -729,30 +778,19 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
                                        const char *sysfsbuf, size_t count)
 {
        int ret;
-       u32 speed;
+       unsigned long speed;
        char newkey[5];
        u8 buffer[2];
-       struct sensor_device_attribute_2 *sensor_attr =
-                                               to_sensor_dev_attr_2(attr);
-
-       speed = simple_strtoul(sysfsbuf, NULL, 10);
-
-       if (speed > 0x4000) /* Bigger than a 14-bit value */
-               return -EINVAL;
 
-       newkey[0] = fan_speed_keys[sensor_attr->nr][0];
-       newkey[1] = '0' + sensor_attr->index;
-       newkey[2] = fan_speed_keys[sensor_attr->nr][2];
-       newkey[3] = fan_speed_keys[sensor_attr->nr][3];
-       newkey[4] = 0;
+       if (strict_strtoul(sysfsbuf, 10, &speed) < 0 || speed >= 0x4000)
+               return -EINVAL;         /* Bigger than a 14-bit value */
 
-       mutex_lock(&applesmc_lock);
+       sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
 
        buffer[0] = (speed >> 6) & 0xff;
        buffer[1] = (speed << 2) & 0xff;
        ret = applesmc_write_key(newkey, buffer, 2);
 
-       mutex_unlock(&applesmc_lock);
        if (ret)
                return ret;
        else
@@ -760,19 +798,15 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
 }
 
 static ssize_t applesmc_show_fan_manual(struct device *dev,
-                       struct device_attribute *devattr, char *sysfsbuf)
+                       struct device_attribute *attr, char *sysfsbuf)
 {
        int ret;
        u16 manual = 0;
        u8 buffer[2];
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-
-       mutex_lock(&applesmc_lock);
 
        ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
-       manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
+       manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
 
-       mutex_unlock(&applesmc_lock);
        if (ret)
                return ret;
        else
@@ -780,18 +814,16 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
 }
 
 static ssize_t applesmc_store_fan_manual(struct device *dev,
-                                        struct device_attribute *devattr,
+                                        struct device_attribute *attr,
                                         const char *sysfsbuf, size_t count)
 {
        int ret;
        u8 buffer[2];
-       u32 input;
+       unsigned long input;
        u16 val;
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-
-       input = simple_strtoul(sysfsbuf, NULL, 10);
 
-       mutex_lock(&applesmc_lock);
+       if (strict_strtoul(sysfsbuf, 10, &input) < 0)
+               return -EINVAL;
 
        ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
        val = (buffer[0] << 8 | buffer[1]);
@@ -799,9 +831,9 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
                goto out;
 
        if (input)
-               val = val | (0x01 << attr->index);
+               val = val | (0x01 << to_index(attr));
        else
-               val = val & ~(0x01 << attr->index);
+               val = val & ~(0x01 << to_index(attr));
 
        buffer[0] = (val >> 8) & 0xFF;
        buffer[1] = val & 0xFF;
@@ -809,7 +841,6 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
        ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
 
 out:
-       mutex_unlock(&applesmc_lock);
        if (ret)
                return ret;
        else
@@ -822,21 +853,12 @@ static ssize_t applesmc_show_fan_position(struct device *dev,
        int ret;
        char newkey[5];
        u8 buffer[17];
-       struct sensor_device_attribute_2 *sensor_attr =
-                                               to_sensor_dev_attr_2(attr);
-
-       newkey[0] = FAN_POSITION[0];
-       newkey[1] = '0' + sensor_attr->index;
-       newkey[2] = FAN_POSITION[2];
-       newkey[3] = FAN_POSITION[3];
-       newkey[4] = 0;
 
-       mutex_lock(&applesmc_lock);
+       sprintf(newkey, FAN_ID_FMT, to_index(attr));
 
        ret = applesmc_read_key(newkey, buffer, 16);
        buffer[16] = 0;
 
-       mutex_unlock(&applesmc_lock);
        if (ret)
                return ret;
        else
@@ -852,18 +874,14 @@ static ssize_t applesmc_calibrate_show(struct device *dev,
 static ssize_t applesmc_calibrate_store(struct device *dev,
        struct device_attribute *attr, const char *sysfsbuf, size_t count)
 {
-       mutex_lock(&applesmc_lock);
        applesmc_calibrate();
-       mutex_unlock(&applesmc_lock);
 
        return count;
 }
 
 static void applesmc_backlight_set(struct work_struct *work)
 {
-       mutex_lock(&applesmc_lock);
        applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
-       mutex_unlock(&applesmc_lock);
 }
 static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
 
@@ -886,13 +904,10 @@ static ssize_t applesmc_key_count_show(struct device *dev,
        u8 buffer[4];
        u32 count;
 
-       mutex_lock(&applesmc_lock);
-
        ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
        count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
                                                ((u32)buffer[2]<<8) + buffer[3];
 
-       mutex_unlock(&applesmc_lock);
        if (ret)
                return ret;
        else
@@ -902,113 +917,53 @@ static ssize_t applesmc_key_count_show(struct device *dev,
 static ssize_t applesmc_key_at_index_read_show(struct device *dev,
                                struct device_attribute *attr, char *sysfsbuf)
 {
-       char key[5];
-       char info[6];
+       const struct applesmc_entry *entry;
        int ret;
 
-       mutex_lock(&applesmc_lock);
-
-       ret = applesmc_get_key_at_index(key_at_index, key);
-
-       if (ret || !key[0]) {
-               mutex_unlock(&applesmc_lock);
-
-               return -EINVAL;
-       }
-
-       ret = applesmc_get_key_type(key, info);
-
-       if (ret) {
-               mutex_unlock(&applesmc_lock);
-
+       entry = applesmc_get_entry_by_index(key_at_index);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
+       ret = applesmc_read_entry(entry, sysfsbuf, entry->len);
+       if (ret)
                return ret;
-       }
-
-       /*
-        * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
-        * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
-        */
-       ret = applesmc_read_key(key, sysfsbuf, info[0]);
-
-       mutex_unlock(&applesmc_lock);
 
-       if (!ret) {
-               return info[0];
-       } else {
-               return ret;
-       }
+       return entry->len;
 }
 
 static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
                                struct device_attribute *attr, char *sysfsbuf)
 {
-       char key[5];
-       char info[6];
-       int ret;
-
-       mutex_lock(&applesmc_lock);
-
-       ret = applesmc_get_key_at_index(key_at_index, key);
+       const struct applesmc_entry *entry;
 
-       if (ret || !key[0]) {
-               mutex_unlock(&applesmc_lock);
+       entry = applesmc_get_entry_by_index(key_at_index);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
 
-               return -EINVAL;
-       }
-
-       ret = applesmc_get_key_type(key, info);
-
-       mutex_unlock(&applesmc_lock);
-
-       if (!ret)
-               return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
-       else
-               return ret;
+       return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", entry->len);
 }
 
 static ssize_t applesmc_key_at_index_type_show(struct device *dev,
                                struct device_attribute *attr, char *sysfsbuf)
 {
-       char key[5];
-       char info[6];
-       int ret;
-
-       mutex_lock(&applesmc_lock);
-
-       ret = applesmc_get_key_at_index(key_at_index, key);
-
-       if (ret || !key[0]) {
-               mutex_unlock(&applesmc_lock);
-
-               return -EINVAL;
-       }
-
-       ret = applesmc_get_key_type(key, info);
+       const struct applesmc_entry *entry;
 
-       mutex_unlock(&applesmc_lock);
+       entry = applesmc_get_entry_by_index(key_at_index);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
 
-       if (!ret)
-               return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
-       else
-               return ret;
+       return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->type);
 }
 
 static ssize_t applesmc_key_at_index_name_show(struct device *dev,
                                struct device_attribute *attr, char *sysfsbuf)
 {
-       char key[5];
-       int ret;
+       const struct applesmc_entry *entry;
 
-       mutex_lock(&applesmc_lock);
+       entry = applesmc_get_entry_by_index(key_at_index);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
 
-       ret = applesmc_get_key_at_index(key_at_index, key);
-
-       mutex_unlock(&applesmc_lock);
-
-       if (!ret && key[0])
-               return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
-       else
-               return -EINVAL;
+       return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key);
 }
 
 static ssize_t applesmc_key_at_index_show(struct device *dev,
@@ -1020,12 +975,13 @@ static ssize_t applesmc_key_at_index_show(struct device *dev,
 static ssize_t applesmc_key_at_index_store(struct device *dev,
        struct device_attribute *attr, const char *sysfsbuf, size_t count)
 {
-       mutex_lock(&applesmc_lock);
-
-       key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
+       unsigned long newkey;
 
-       mutex_unlock(&applesmc_lock);
+       if (strict_strtoul(sysfsbuf, 10, &newkey) < 0
+           || newkey >= smcreg.key_count)
+               return -EINVAL;
 
+       key_at_index = newkey;
        return count;
 }
 
@@ -1035,387 +991,101 @@ static struct led_classdev applesmc_backlight = {
        .brightness_set         = applesmc_brightness_set,
 };
 
-static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
-
-static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
-static DEVICE_ATTR(calibrate, 0644,
-                       applesmc_calibrate_show, applesmc_calibrate_store);
-
-static struct attribute *accelerometer_attributes[] = {
-       &dev_attr_position.attr,
-       &dev_attr_calibrate.attr,
-       NULL
-};
-
-static const struct attribute_group accelerometer_attributes_group =
-       { .attrs = accelerometer_attributes };
-
-static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
-
-static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
-static DEVICE_ATTR(key_at_index, 0644,
-               applesmc_key_at_index_show, applesmc_key_at_index_store);
-static DEVICE_ATTR(key_at_index_name, 0444,
-                                       applesmc_key_at_index_name_show, NULL);
-static DEVICE_ATTR(key_at_index_type, 0444,
-                                       applesmc_key_at_index_type_show, NULL);
-static DEVICE_ATTR(key_at_index_data_length, 0444,
-                               applesmc_key_at_index_data_length_show, NULL);
-static DEVICE_ATTR(key_at_index_data, 0444,
-                               applesmc_key_at_index_read_show, NULL);
-
-static struct attribute *key_enumeration_attributes[] = {
-       &dev_attr_key_count.attr,
-       &dev_attr_key_at_index.attr,
-       &dev_attr_key_at_index_name.attr,
-       &dev_attr_key_at_index_type.attr,
-       &dev_attr_key_at_index_data_length.attr,
-       &dev_attr_key_at_index_data.attr,
-       NULL
-};
-
-static const struct attribute_group key_enumeration_group =
-       { .attrs = key_enumeration_attributes };
-
-/*
- * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
- *  - show actual speed
- *  - show/store minimum speed
- *  - show maximum speed
- *  - show safe speed
- *  - show/store target speed
- *  - show/store manual mode
- */
-#define sysfs_fan_speeds_offset(offset) \
-static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
-                       applesmc_show_fan_speed, NULL, 0, offset-1); \
-\
-static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
-       applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
-\
-static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
-                       applesmc_show_fan_speed, NULL, 2, offset-1); \
-\
-static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
-                       applesmc_show_fan_speed, NULL, 3, offset-1); \
-\
-static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
-       applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
-\
-static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
-       applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
-\
-static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
-       applesmc_show_fan_position, NULL, offset-1); \
-\
-static struct attribute *fan##offset##_attributes[] = { \
-       &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
-       &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
-       &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
-       &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
-       &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
-       &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
-       &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
-       NULL \
+static struct applesmc_node_group info_group[] = {
+       { "name", applesmc_name_show },
+       { "key_count", applesmc_key_count_show },
+       { "key_at_index", applesmc_key_at_index_show, applesmc_key_at_index_store },
+       { "key_at_index_name", applesmc_key_at_index_name_show },
+       { "key_at_index_type", applesmc_key_at_index_type_show },
+       { "key_at_index_data_length", applesmc_key_at_index_data_length_show },
+       { "key_at_index_data", applesmc_key_at_index_read_show },
+       { }
 };
 
-/*
- * Create the needed functions for each fan using the macro defined above
- * (4 fans are supported)
- */
-sysfs_fan_speeds_offset(1);
-sysfs_fan_speeds_offset(2);
-sysfs_fan_speeds_offset(3);
-sysfs_fan_speeds_offset(4);
-
-static const struct attribute_group fan_attribute_groups[] = {
-       { .attrs = fan1_attributes },
-       { .attrs = fan2_attributes },
-       { .attrs = fan3_attributes },
-       { .attrs = fan4_attributes },
+static struct applesmc_node_group accelerometer_group[] = {
+       { "position", applesmc_position_show },
+       { "calibrate", applesmc_calibrate_show, applesmc_calibrate_store },
+       { }
 };
 
-/*
- * Temperature sensors sysfs entries.
- */
-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 4);
-static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 5);
-static SENSOR_DEVICE_ATTR(temp7_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 6);
-static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 7);
-static SENSOR_DEVICE_ATTR(temp9_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 8);
-static SENSOR_DEVICE_ATTR(temp10_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 9);
-static SENSOR_DEVICE_ATTR(temp11_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 10);
-static SENSOR_DEVICE_ATTR(temp12_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 11);
-static SENSOR_DEVICE_ATTR(temp13_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 12);
-static SENSOR_DEVICE_ATTR(temp14_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 13);
-static SENSOR_DEVICE_ATTR(temp15_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 14);
-static SENSOR_DEVICE_ATTR(temp16_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 15);
-static SENSOR_DEVICE_ATTR(temp17_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 16);
-static SENSOR_DEVICE_ATTR(temp18_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 17);
-static SENSOR_DEVICE_ATTR(temp19_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 18);
-static SENSOR_DEVICE_ATTR(temp20_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 19);
-static SENSOR_DEVICE_ATTR(temp21_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 20);
-static SENSOR_DEVICE_ATTR(temp22_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 21);
-static SENSOR_DEVICE_ATTR(temp23_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 22);
-static SENSOR_DEVICE_ATTR(temp24_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 23);
-static SENSOR_DEVICE_ATTR(temp25_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 24);
-static SENSOR_DEVICE_ATTR(temp26_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 25);
-static SENSOR_DEVICE_ATTR(temp27_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 26);
-static SENSOR_DEVICE_ATTR(temp28_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 27);
-static SENSOR_DEVICE_ATTR(temp29_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 28);
-static SENSOR_DEVICE_ATTR(temp30_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 29);
-static SENSOR_DEVICE_ATTR(temp31_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 30);
-static SENSOR_DEVICE_ATTR(temp32_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 31);
-static SENSOR_DEVICE_ATTR(temp33_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 32);
-static SENSOR_DEVICE_ATTR(temp34_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 33);
-static SENSOR_DEVICE_ATTR(temp35_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 34);
-static SENSOR_DEVICE_ATTR(temp36_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 35);
-static SENSOR_DEVICE_ATTR(temp37_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 36);
-static SENSOR_DEVICE_ATTR(temp38_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 37);
-static SENSOR_DEVICE_ATTR(temp39_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 38);
-static SENSOR_DEVICE_ATTR(temp40_label, S_IRUGO,
-                                       applesmc_show_sensor_label, NULL, 39);
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 4);
-static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 5);
-static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 6);
-static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 7);
-static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 8);
-static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 9);
-static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 10);
-static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 11);
-static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 12);
-static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 13);
-static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 14);
-static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 15);
-static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 16);
-static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 17);
-static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 18);
-static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 19);
-static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 20);
-static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 21);
-static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 22);
-static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 23);
-static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 24);
-static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 25);
-static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 26);
-static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 27);
-static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 28);
-static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 29);
-static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 30);
-static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 31);
-static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 32);
-static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 33);
-static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 34);
-static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 35);
-static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 36);
-static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 37);
-static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 38);
-static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
-                                       applesmc_show_temperature, NULL, 39);
-
-static struct attribute *label_attributes[] = {
-       &sensor_dev_attr_temp1_label.dev_attr.attr,
-       &sensor_dev_attr_temp2_label.dev_attr.attr,
-       &sensor_dev_attr_temp3_label.dev_attr.attr,
-       &sensor_dev_attr_temp4_label.dev_attr.attr,
-       &sensor_dev_attr_temp5_label.dev_attr.attr,
-       &sensor_dev_attr_temp6_label.dev_attr.attr,
-       &sensor_dev_attr_temp7_label.dev_attr.attr,
-       &sensor_dev_attr_temp8_label.dev_attr.attr,
-       &sensor_dev_attr_temp9_label.dev_attr.attr,
-       &sensor_dev_attr_temp10_label.dev_attr.attr,
-       &sensor_dev_attr_temp11_label.dev_attr.attr,
-       &sensor_dev_attr_temp12_label.dev_attr.attr,
-       &sensor_dev_attr_temp13_label.dev_attr.attr,
-       &sensor_dev_attr_temp14_label.dev_attr.attr,
-       &sensor_dev_attr_temp15_label.dev_attr.attr,
-       &sensor_dev_attr_temp16_label.dev_attr.attr,
-       &sensor_dev_attr_temp17_label.dev_attr.attr,
-       &sensor_dev_attr_temp18_label.dev_attr.attr,
-       &sensor_dev_attr_temp19_label.dev_attr.attr,
-       &sensor_dev_attr_temp20_label.dev_attr.attr,
-       &sensor_dev_attr_temp21_label.dev_attr.attr,
-       &sensor_dev_attr_temp22_label.dev_attr.attr,
-       &sensor_dev_attr_temp23_label.dev_attr.attr,
-       &sensor_dev_attr_temp24_label.dev_attr.attr,
-       &sensor_dev_attr_temp25_label.dev_attr.attr,
-       &sensor_dev_attr_temp26_label.dev_attr.attr,
-       &sensor_dev_attr_temp27_label.dev_attr.attr,
-       &sensor_dev_attr_temp28_label.dev_attr.attr,
-       &sensor_dev_attr_temp29_label.dev_attr.attr,
-       &sensor_dev_attr_temp30_label.dev_attr.attr,
-       &sensor_dev_attr_temp31_label.dev_attr.attr,
-       &sensor_dev_attr_temp32_label.dev_attr.attr,
-       &sensor_dev_attr_temp33_label.dev_attr.attr,
-       &sensor_dev_attr_temp34_label.dev_attr.attr,
-       &sensor_dev_attr_temp35_label.dev_attr.attr,
-       &sensor_dev_attr_temp36_label.dev_attr.attr,
-       &sensor_dev_attr_temp37_label.dev_attr.attr,
-       &sensor_dev_attr_temp38_label.dev_attr.attr,
-       &sensor_dev_attr_temp39_label.dev_attr.attr,
-       &sensor_dev_attr_temp40_label.dev_attr.attr,
-       NULL
+static struct applesmc_node_group light_sensor_group[] = {
+       { "light", applesmc_light_show },
+       { }
 };
 
-static struct attribute *temperature_attributes[] = {
-       &sensor_dev_attr_temp1_input.dev_attr.attr,
-       &sensor_dev_attr_temp2_input.dev_attr.attr,
-       &sensor_dev_attr_temp3_input.dev_attr.attr,
-       &sensor_dev_attr_temp4_input.dev_attr.attr,
-       &sensor_dev_attr_temp5_input.dev_attr.attr,
-       &sensor_dev_attr_temp6_input.dev_attr.attr,
-       &sensor_dev_attr_temp7_input.dev_attr.attr,
-       &sensor_dev_attr_temp8_input.dev_attr.attr,
-       &sensor_dev_attr_temp9_input.dev_attr.attr,
-       &sensor_dev_attr_temp10_input.dev_attr.attr,
-       &sensor_dev_attr_temp11_input.dev_attr.attr,
-       &sensor_dev_attr_temp12_input.dev_attr.attr,
-       &sensor_dev_attr_temp13_input.dev_attr.attr,
-       &sensor_dev_attr_temp14_input.dev_attr.attr,
-       &sensor_dev_attr_temp15_input.dev_attr.attr,
-       &sensor_dev_attr_temp16_input.dev_attr.attr,
-       &sensor_dev_attr_temp17_input.dev_attr.attr,
-       &sensor_dev_attr_temp18_input.dev_attr.attr,
-       &sensor_dev_attr_temp19_input.dev_attr.attr,
-       &sensor_dev_attr_temp20_input.dev_attr.attr,
-       &sensor_dev_attr_temp21_input.dev_attr.attr,
-       &sensor_dev_attr_temp22_input.dev_attr.attr,
-       &sensor_dev_attr_temp23_input.dev_attr.attr,
-       &sensor_dev_attr_temp24_input.dev_attr.attr,
-       &sensor_dev_attr_temp25_input.dev_attr.attr,
-       &sensor_dev_attr_temp26_input.dev_attr.attr,
-       &sensor_dev_attr_temp27_input.dev_attr.attr,
-       &sensor_dev_attr_temp28_input.dev_attr.attr,
-       &sensor_dev_attr_temp29_input.dev_attr.attr,
-       &sensor_dev_attr_temp30_input.dev_attr.attr,
-       &sensor_dev_attr_temp31_input.dev_attr.attr,
-       &sensor_dev_attr_temp32_input.dev_attr.attr,
-       &sensor_dev_attr_temp33_input.dev_attr.attr,
-       &sensor_dev_attr_temp34_input.dev_attr.attr,
-       &sensor_dev_attr_temp35_input.dev_attr.attr,
-       &sensor_dev_attr_temp36_input.dev_attr.attr,
-       &sensor_dev_attr_temp37_input.dev_attr.attr,
-       &sensor_dev_attr_temp38_input.dev_attr.attr,
-       &sensor_dev_attr_temp39_input.dev_attr.attr,
-       &sensor_dev_attr_temp40_input.dev_attr.attr,
-       NULL
+static struct applesmc_node_group fan_group[] = {
+       { "fan%d_label", applesmc_show_fan_position },
+       { "fan%d_input", applesmc_show_fan_speed, NULL, 0 },
+       { "fan%d_min", applesmc_show_fan_speed, applesmc_store_fan_speed, 1 },
+       { "fan%d_max", applesmc_show_fan_speed, NULL, 2 },
+       { "fan%d_safe", applesmc_show_fan_speed, NULL, 3 },
+       { "fan%d_output", applesmc_show_fan_speed, applesmc_store_fan_speed, 4 },
+       { "fan%d_manual", applesmc_show_fan_manual, applesmc_store_fan_manual },
+       { }
 };
 
-static const struct attribute_group temperature_attributes_group =
-       { .attrs = temperature_attributes };
-
-static const struct attribute_group label_attributes_group = {
-       .attrs = label_attributes
+static struct applesmc_node_group temp_group[] = {
+       { "temp%d_label", applesmc_show_sensor_label },
+       { "temp%d_input", applesmc_show_temperature },
+       { }
 };
 
 /* Module stuff */
 
 /*
- * applesmc_dmi_match - found a match.  return one, short-circuiting the hunt.
+ * applesmc_destroy_nodes - remove files and free associated memory
  */
-static int applesmc_dmi_match(const struct dmi_system_id *id)
+static void applesmc_destroy_nodes(struct applesmc_node_group *groups)
 {
-       int i = 0;
-       struct dmi_match_data* dmi_data = id->driver_data;
-       printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
-       applesmc_accelerometer = dmi_data->accelerometer;
-       printk(KERN_INFO "applesmc:  - Model %s accelerometer\n",
-                               applesmc_accelerometer ? "with" : "without");
-       applesmc_light = dmi_data->light;
-       printk(KERN_INFO "applesmc:  - Model %s light sensors and backlight\n",
-                                       applesmc_light ? "with" : "without");
-
-       applesmc_temperature_set =  dmi_data->temperature_set;
-       while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
-               i++;
-       printk(KERN_INFO "applesmc:  - Model with %d temperature sensors\n", i);
-       return 1;
+       struct applesmc_node_group *grp;
+       struct applesmc_dev_attr *node;
+
+       for (grp = groups; grp->nodes; grp++) {
+               for (node = grp->nodes; node->sda.dev_attr.attr.name; node++)
+                       sysfs_remove_file(&pdev->dev.kobj,
+                                         &node->sda.dev_attr.attr);
+               kfree(grp->nodes);
+               grp->nodes = NULL;
+       }
+}
+
+/*
+ * applesmc_create_nodes - create a two-dimensional group of sysfs files
+ */
+static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
+{
+       struct applesmc_node_group *grp;
+       struct applesmc_dev_attr *node;
+       struct attribute *attr;
+       int ret, i;
+
+       for (grp = groups; grp->format; grp++) {
+               grp->nodes = kcalloc(num + 1, sizeof(*node), GFP_KERNEL);
+               if (!grp->nodes) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               for (i = 0; i < num; i++) {
+                       node = &grp->nodes[i];
+                       sprintf(node->name, grp->format, i + 1);
+                       node->sda.index = (grp->option << 16) | (i & 0xffff);
+                       node->sda.dev_attr.show = grp->show;
+                       node->sda.dev_attr.store = grp->store;
+                       attr = &node->sda.dev_attr.attr;
+                       attr->name = node->name;
+                       attr->mode = S_IRUGO | (grp->store ? S_IWUSR : 0);
+                       ret = sysfs_create_file(&pdev->dev.kobj, attr);
+                       if (ret) {
+                               attr->name = NULL;
+                               goto out;
+                       }
+               }
+       }
+
+       return 0;
+out:
+       applesmc_destroy_nodes(groups);
+       return ret;
 }
 
 /* Create accelerometer ressources */
@@ -1424,8 +1094,10 @@ static int applesmc_create_accelerometer(void)
        struct input_dev *idev;
        int ret;
 
-       ret = sysfs_create_group(&pdev->dev.kobj,
-                                       &accelerometer_attributes_group);
+       if (!smcreg.has_accelerometer)
+               return 0;
+
+       ret = applesmc_create_nodes(accelerometer_group, 1);
        if (ret)
                goto out;
 
@@ -1462,184 +1134,96 @@ out_idev:
        input_free_polled_device(applesmc_idev);
 
 out_sysfs:
-       sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
+       applesmc_destroy_nodes(accelerometer_group);
 
 out:
-       printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
+       pr_warn("driver init failed (ret=%d)!\n", ret);
        return ret;
 }
 
 /* Release all ressources used by the accelerometer */
 static void applesmc_release_accelerometer(void)
 {
+       if (!smcreg.has_accelerometer)
+               return;
        input_unregister_polled_device(applesmc_idev);
        input_free_polled_device(applesmc_idev);
-       sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
+       applesmc_destroy_nodes(accelerometer_group);
 }
 
-static __initdata struct dmi_match_data applesmc_dmi_data[] = {
-/* MacBook Pro: accelerometer, backlight and temperature set 0 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 0 },
-/* MacBook2: accelerometer and temperature set 1 */
-       { .accelerometer = 1, .light = 0, .temperature_set = 1 },
-/* MacBook: accelerometer and temperature set 2 */
-       { .accelerometer = 1, .light = 0, .temperature_set = 2 },
-/* MacMini: temperature set 3 */
-       { .accelerometer = 0, .light = 0, .temperature_set = 3 },
-/* MacPro: temperature set 4 */
-       { .accelerometer = 0, .light = 0, .temperature_set = 4 },
-/* iMac: temperature set 5 */
-       { .accelerometer = 0, .light = 0, .temperature_set = 5 },
-/* MacBook3, MacBook4: accelerometer and temperature set 6 */
-       { .accelerometer = 1, .light = 0, .temperature_set = 6 },
-/* MacBook Air: accelerometer, backlight and temperature set 7 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 7 },
-/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 8 },
-/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 9 },
-/* iMac 5: light sensor only, temperature set 10 */
-       { .accelerometer = 0, .light = 0, .temperature_set = 10 },
-/* MacBook 5: accelerometer, backlight and temperature set 11 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 11 },
-/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 12 },
-/* iMac 8: light sensor only, temperature set 13 */
-       { .accelerometer = 0, .light = 0, .temperature_set = 13 },
-/* iMac 6: light sensor only, temperature set 14 */
-       { .accelerometer = 0, .light = 0, .temperature_set = 14 },
-/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 15 },
-/* MacPro3,1: temperature set 16 */
-       { .accelerometer = 0, .light = 0, .temperature_set = 16 },
-/* iMac 9,1: light sensor only, temperature set 17 */
-       { .accelerometer = 0, .light = 0, .temperature_set = 17 },
-/* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 18 },
-/* MacBook Pro 5,3: accelerometer, backlight and temperature set 19 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 19 },
-/* MacBook Pro 5,4: accelerometer, backlight and temperature set 20 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 20 },
-/* MacBook Pro 6,2: accelerometer, backlight and temperature set 21 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 21 },
-/* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */
-       { .accelerometer = 1, .light = 1, .temperature_set = 22 },
-};
+static int applesmc_create_light_sensor(void)
+{
+       if (!smcreg.num_light_sensors)
+               return 0;
+       return applesmc_create_nodes(light_sensor_group, 1);
+}
+
+static void applesmc_release_light_sensor(void)
+{
+       if (!smcreg.num_light_sensors)
+               return;
+       applesmc_destroy_nodes(light_sensor_group);
+}
+
+static int applesmc_create_key_backlight(void)
+{
+       if (!smcreg.has_key_backlight)
+               return 0;
+       applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
+       if (!applesmc_led_wq)
+               return -ENOMEM;
+       return led_classdev_register(&pdev->dev, &applesmc_backlight);
+}
+
+static void applesmc_release_key_backlight(void)
+{
+       if (!smcreg.has_key_backlight)
+               return;
+       led_classdev_unregister(&applesmc_backlight);
+       destroy_workqueue(applesmc_led_wq);
+}
+
+static int applesmc_dmi_match(const struct dmi_system_id *id)
+{
+       return 1;
+}
 
 /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
  * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
 static __initdata struct dmi_system_id applesmc_whitelist[] = {
-       { applesmc_dmi_match, "Apple MacBook Air 2", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
-               &applesmc_dmi_data[15]},
        { applesmc_dmi_match, "Apple MacBook Air", {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
-               &applesmc_dmi_data[7]},
-       { applesmc_dmi_match, "Apple MacBook Pro 7", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro7") },
-               &applesmc_dmi_data[22]},
-       { applesmc_dmi_match, "Apple MacBook Pro 5,4", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4") },
-               &applesmc_dmi_data[20]},
-       { applesmc_dmi_match, "Apple MacBook Pro 5,3", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3") },
-               &applesmc_dmi_data[19]},
-       { applesmc_dmi_match, "Apple MacBook Pro 6", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6") },
-               &applesmc_dmi_data[21]},
-       { applesmc_dmi_match, "Apple MacBook Pro 5", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
-               &applesmc_dmi_data[12]},
-       { applesmc_dmi_match, "Apple MacBook Pro 4", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
-               &applesmc_dmi_data[8]},
-       { applesmc_dmi_match, "Apple MacBook Pro 3", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
-               &applesmc_dmi_data[9]},
-       { applesmc_dmi_match, "Apple MacBook Pro 2,2", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple Computer, Inc."),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2") },
-               &applesmc_dmi_data[18]},
+       },
        { applesmc_dmi_match, "Apple MacBook Pro", {
-         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
-               &applesmc_dmi_data[0]},
-       { applesmc_dmi_match, "Apple MacBook (v2)", {
-         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
-               &applesmc_dmi_data[1]},
-       { applesmc_dmi_match, "Apple MacBook (v3)", {
-         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
-               &applesmc_dmi_data[6]},
-       { applesmc_dmi_match, "Apple MacBook 4", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
-               &applesmc_dmi_data[6]},
-       { applesmc_dmi_match, "Apple MacBook 5", {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
-               &applesmc_dmi_data[11]},
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro") },
+       },
        { applesmc_dmi_match, "Apple MacBook", {
-         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
-               &applesmc_dmi_data[2]},
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") },
+       },
        { applesmc_dmi_match, "Apple Macmini", {
-         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
-               &applesmc_dmi_data[3]},
-       { applesmc_dmi_match, "Apple MacPro2", {
-         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
-               &applesmc_dmi_data[4]},
-       { applesmc_dmi_match, "Apple MacPro3", {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") },
-               &applesmc_dmi_data[16]},
+         DMI_MATCH(DMI_PRODUCT_NAME, "Macmini") },
+       },
        { applesmc_dmi_match, "Apple MacPro", {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
-               &applesmc_dmi_data[4]},
-       { applesmc_dmi_match, "Apple iMac 9,1", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
-         DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1") },
-               &applesmc_dmi_data[17]},
-       { applesmc_dmi_match, "Apple iMac 8", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
-               &applesmc_dmi_data[13]},
-       { applesmc_dmi_match, "Apple iMac 6", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
-               &applesmc_dmi_data[14]},
-       { applesmc_dmi_match, "Apple iMac 5", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
-               &applesmc_dmi_data[10]},
+       },
        { applesmc_dmi_match, "Apple iMac", {
-         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
-               &applesmc_dmi_data[5]},
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "iMac") },
+       },
        { .ident = NULL }
 };
 
 static int __init applesmc_init(void)
 {
        int ret;
-       int count;
-       int i;
 
        if (!dmi_check_system(applesmc_whitelist)) {
-               printk(KERN_WARNING "applesmc: supported laptop not found!\n");
+               pr_warn("supported laptop not found!\n");
                ret = -ENODEV;
                goto out;
        }
@@ -1661,83 +1245,34 @@ static int __init applesmc_init(void)
                goto out_driver;
        }
 
-       ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
+       /* create register cache */
+       ret = applesmc_init_smcreg();
        if (ret)
                goto out_device;
 
-       /* Create key enumeration sysfs files */
-       ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
+       ret = applesmc_create_nodes(info_group, 1);
        if (ret)
-               goto out_name;
-
-       /* create fan files */
-       count = applesmc_get_fan_count();
-       if (count < 0)
-               printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
-       else
-               printk(KERN_INFO "applesmc: %d fans found.\n", count);
+               goto out_smcreg;
 
-       if (count > 4) {
-               count = 4;
-               printk(KERN_WARNING "applesmc: More than 4 fans found,"
-                      " but at most 4 fans are supported"
-                      " by the driver.\n");
-       }
-
-       while (fans_handled < count) {
-               ret = sysfs_create_group(&pdev->dev.kobj,
-                                        &fan_attribute_groups[fans_handled]);
-               if (ret)
-                       goto out_fans;
-               fans_handled++;
-       }
-
-       for (i = 0;
-            temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
-            i++) {
-               if (temperature_attributes[i] == NULL ||
-                   label_attributes[i] == NULL) {
-                       printk(KERN_ERR "applesmc: More temperature sensors "
-                               "in temperature_sensors_sets (at least %i)"
-                               "than available sysfs files in "
-                               "temperature_attributes (%i), please report "
-                               "this bug.\n", i, i-1);
-                       goto out_temperature;
-               }
-               ret = sysfs_create_file(&pdev->dev.kobj,
-                                               temperature_attributes[i]);
-               if (ret)
-                       goto out_temperature;
-               ret = sysfs_create_file(&pdev->dev.kobj,
-                                               label_attributes[i]);
-               if (ret)
-                       goto out_temperature;
-       }
+       ret = applesmc_create_nodes(fan_group, smcreg.fan_count);
+       if (ret)
+               goto out_info;
 
-       if (applesmc_accelerometer) {
-               ret = applesmc_create_accelerometer();
-               if (ret)
-                       goto out_temperature;
-       }
+       ret = applesmc_create_nodes(temp_group, smcreg.temp_count);
+       if (ret)
+               goto out_fans;
 
-       if (applesmc_light) {
-               /* Add light sensor file */
-               ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
-               if (ret)
-                       goto out_accelerometer;
+       ret = applesmc_create_accelerometer();
+       if (ret)
+               goto out_temperature;
 
-               /* Create the workqueue */
-               applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
-               if (!applesmc_led_wq) {
-                       ret = -ENOMEM;
-                       goto out_light_sysfs;
-               }
+       ret = applesmc_create_light_sensor();
+       if (ret)
+               goto out_accelerometer;
 
-               /* register as a led device */
-               ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
-               if (ret < 0)
-                       goto out_light_wq;
-       }
+       ret = applesmc_create_key_backlight();
+       if (ret)
+               goto out_light_sysfs;
 
        hwmon_dev = hwmon_device_register(&pdev->dev);
        if (IS_ERR(hwmon_dev)) {
@@ -1745,32 +1280,22 @@ static int __init applesmc_init(void)
                goto out_light_ledclass;
        }
 
-       printk(KERN_INFO "applesmc: driver successfully loaded.\n");
-
        return 0;
 
 out_light_ledclass:
-       if (applesmc_light)
-               led_classdev_unregister(&applesmc_backlight);
-out_light_wq:
-       if (applesmc_light)
-               destroy_workqueue(applesmc_led_wq);
+       applesmc_release_key_backlight();
 out_light_sysfs:
-       if (applesmc_light)
-               sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
+       applesmc_release_light_sensor();
 out_accelerometer:
-       if (applesmc_accelerometer)
-               applesmc_release_accelerometer();
+       applesmc_release_accelerometer();
 out_temperature:
-       sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
-       sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
+       applesmc_destroy_nodes(temp_group);
 out_fans:
-       while (fans_handled)
-               sysfs_remove_group(&pdev->dev.kobj,
-                                  &fan_attribute_groups[--fans_handled]);
-       sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
-out_name:
-       sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
+       applesmc_destroy_nodes(fan_group);
+out_info:
+       applesmc_destroy_nodes(info_group);
+out_smcreg:
+       applesmc_destroy_smcreg();
 out_device:
        platform_device_unregister(pdev);
 out_driver:
@@ -1778,32 +1303,23 @@ out_driver:
 out_region:
        release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
 out:
-       printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
+       pr_warn("driver init failed (ret=%d)!\n", ret);
        return ret;
 }
 
 static void __exit applesmc_exit(void)
 {
        hwmon_device_unregister(hwmon_dev);
-       if (applesmc_light) {
-               led_classdev_unregister(&applesmc_backlight);
-               destroy_workqueue(applesmc_led_wq);
-               sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
-       }
-       if (applesmc_accelerometer)
-               applesmc_release_accelerometer();
-       sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
-       sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
-       while (fans_handled)
-               sysfs_remove_group(&pdev->dev.kobj,
-                                  &fan_attribute_groups[--fans_handled]);
-       sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
-       sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
+       applesmc_release_key_backlight();
+       applesmc_release_light_sensor();
+       applesmc_release_accelerometer();
+       applesmc_destroy_nodes(temp_group);
+       applesmc_destroy_nodes(fan_group);
+       applesmc_destroy_nodes(info_group);
+       applesmc_destroy_smcreg();
        platform_device_unregister(pdev);
        platform_driver_unregister(&applesmc_driver);
        release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
-
-       printk(KERN_INFO "applesmc: driver unloaded.\n");
 }
 
 module_init(applesmc_init);
index 7dada559b3a19a85815002ce1ff76727306d4a23..c02a052d3085de76664b699c3f565a2968e8156e 100644 (file)
@@ -36,6 +36,8 @@
     asb100     7       3       1       4       0x31    0x0694  yes     no
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
@@ -701,8 +703,7 @@ static int asb100_detect(struct i2c_client *client,
        int val1, val2;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-               pr_debug("asb100.o: detect failed, "
-                               "smbus byte data not supported!\n");
+               pr_debug("detect failed, smbus byte data not supported!\n");
                return -ENODEV;
        }
 
@@ -715,7 +716,7 @@ static int asb100_detect(struct i2c_client *client,
                        (((!(val1 & 0x80)) && (val2 != 0x94)) ||
                        /* Check for ASB100 ID (high byte ) */
                        ((val1 & 0x80) && (val2 != 0x06)))) {
-               pr_debug("asb100: detect failed, bad chip id 0x%02x!\n", val2);
+               pr_debug("detect failed, bad chip id 0x%02x!\n", val2);
                return -ENODEV;
        }
 
@@ -744,7 +745,7 @@ static int asb100_probe(struct i2c_client *client,
 
        data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL);
        if (!data) {
-               pr_debug("asb100.o: probe failed, kzalloc failed!\n");
+               pr_debug("probe failed, kzalloc failed!\n");
                err = -ENOMEM;
                goto ERROR0;
        }
index 23b8555215d2fa61e52e2e08f85935fdd0ca2860..2d68cf3c223b7cb401a76481d9064aa040ea2eef 100644 (file)
@@ -5,6 +5,8 @@
  * See COPYING in the top level directory of the kernel tree.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/debugfs.h>
 #include <linux/kernel.h>
 #include <linux/hwmon.h>
@@ -1414,14 +1416,13 @@ static int __init atk0110_init(void)
 
        /* Make sure it's safe to access the device through ACPI */
        if (!acpi_resources_are_enforced()) {
-               pr_err("atk: Resources not safely usable due to "
-                      "acpi_enforce_resources kernel parameter\n");
+               pr_err("Resources not safely usable due to acpi_enforce_resources kernel parameter\n");
                return -EBUSY;
        }
 
        ret = acpi_bus_register_driver(&atk_driver);
        if (ret)
-               pr_info("atk: acpi_bus_register_driver failed: %d\n", ret);
+               pr_info("acpi_bus_register_driver failed: %d\n", ret);
 
        return ret;
 }
index 42de98d73ff5016d68a2884b91ad5f70b9b99713..194ca0aa8b0c5b6e14b1777a63fedcdf205dc0f1 100644 (file)
@@ -20,6 +20,8 @@
  * 02110-1301 USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -445,8 +447,8 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
         * without thermal sensors will be filtered out.
         */
        if (!cpu_has(c, X86_FEATURE_DTS)) {
-               printk(KERN_INFO DRVNAME ": CPU (model=0x%x)"
-                      " has no thermal sensor.\n", c->x86_model);
+               pr_info("CPU (model=0x%x) has no thermal sensor\n",
+                       c->x86_model);
                return 0;
        }
 
@@ -466,7 +468,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
        pdev = platform_device_alloc(DRVNAME, cpu);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit;
        }
 
@@ -478,8 +480,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_free;
        }
 
index 980c17d5eeae98992345f2a2f413994f3513c79f..e9a610bfd0cc894db71e7203e11d783a34157c46 100644 (file)
@@ -25,6 +25,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -2446,7 +2448,7 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
        /* Get the base address of the runtime registers */
        if (!(base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
                           dme1737_sio_inb(sio_cip, 0x61))) {
-               printk(KERN_ERR "dme1737: Base address not set.\n");
+               pr_err("Base address not set\n");
                err = -ENODEV;
                goto exit;
        }
@@ -2475,20 +2477,18 @@ static int __init dme1737_isa_device_add(unsigned short addr)
                goto exit;
 
        if (!(pdev = platform_device_alloc("dme1737", addr))) {
-               printk(KERN_ERR "dme1737: Failed to allocate device.\n");
+               pr_err("Failed to allocate device\n");
                err = -ENOMEM;
                goto exit;
        }
 
        if ((err = platform_device_add_resources(pdev, &res, 1))) {
-               printk(KERN_ERR "dme1737: Failed to add device resource "
-                      "(err = %d).\n", err);
+               pr_err("Failed to add device resource (err = %d)\n", err);
                goto exit_device_put;
        }
 
        if ((err = platform_device_add(pdev))) {
-               printk(KERN_ERR "dme1737: Failed to add device (err = %d).\n",
-                      err);
+               pr_err("Failed to add device (err = %d)\n", err);
                goto exit_device_put;
        }
 
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
new file mode 100644 (file)
index 0000000..257957c
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ *  ds620.c - Support for temperature sensor and thermostat DS620
+ *
+ *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
+ *
+ *  based on ds1621.c by Christian W. Zuckschwerdt  <zany@triq.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/i2c/ds620.h>
+
+/*
+ * Many DS620 constants specified below
+ *  15   14   13   12   11   10   09    08
+ * |Done|NVB |THF |TLF |R1  |R0  |AUTOC|1SHOT|
+ *
+ *  07   06   05   04   03   02   01    00
+ * |PO2 |PO1 |A2  |A1  |A0  |    |     |     |
+ */
+#define DS620_REG_CONFIG_DONE          0x8000
+#define DS620_REG_CONFIG_NVB           0x4000
+#define DS620_REG_CONFIG_THF           0x2000
+#define DS620_REG_CONFIG_TLF           0x1000
+#define DS620_REG_CONFIG_R1            0x0800
+#define DS620_REG_CONFIG_R0            0x0400
+#define DS620_REG_CONFIG_AUTOC         0x0200
+#define DS620_REG_CONFIG_1SHOT         0x0100
+#define DS620_REG_CONFIG_PO2           0x0080
+#define DS620_REG_CONFIG_PO1           0x0040
+#define DS620_REG_CONFIG_A2            0x0020
+#define DS620_REG_CONFIG_A1            0x0010
+#define DS620_REG_CONFIG_A0            0x0008
+
+/* The DS620 registers */
+static const u8 DS620_REG_TEMP[3] = {
+       0xAA,                   /* input, word, RO */
+       0xA2,                   /* min, word, RW */
+       0xA0,                   /* max, word, RW */
+};
+
+#define DS620_REG_CONF         0xAC    /* word, RW */
+#define DS620_COM_START                0x51    /* no data */
+#define DS620_COM_STOP         0x22    /* no data */
+
+/* Each client has this additional data */
+struct ds620_data {
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       char valid;             /* !=0 if following fields are valid */
+       unsigned long last_updated;     /* In jiffies */
+
+       u16 temp[3];            /* Register values, word */
+};
+
+/*
+ *  Temperature registers are word-sized.
+ *  DS620 uses a high-byte first convention, which is exactly opposite to
+ *  the SMBus standard.
+ */
+static int ds620_read_temp(struct i2c_client *client, u8 reg)
+{
+       int ret;
+
+       ret = i2c_smbus_read_word_data(client, reg);
+       if (ret < 0)
+               return ret;
+       return swab16(ret);
+}
+
+static int ds620_write_temp(struct i2c_client *client, u8 reg, u16 value)
+{
+       return i2c_smbus_write_word_data(client, reg, swab16(value));
+}
+
+static void ds620_init_client(struct i2c_client *client)
+{
+       struct ds620_platform_data *ds620_info = client->dev.platform_data;
+       u16 conf, new_conf;
+
+       new_conf = conf =
+           swab16(i2c_smbus_read_word_data(client, DS620_REG_CONF));
+
+       /* switch to continuous conversion mode */
+       new_conf &= ~DS620_REG_CONFIG_1SHOT;
+       /* already high at power-on, but don't trust the BIOS! */
+       new_conf |= DS620_REG_CONFIG_PO2;
+       /* thermostat mode according to platform data */
+       if (ds620_info && ds620_info->pomode == 1)
+               new_conf &= ~DS620_REG_CONFIG_PO1; /* PO_LOW */
+       else if (ds620_info && ds620_info->pomode == 2)
+               new_conf |= DS620_REG_CONFIG_PO1; /* PO_HIGH */
+       else
+               new_conf &= ~DS620_REG_CONFIG_PO2; /* always low */
+       /* with highest precision */
+       new_conf |= DS620_REG_CONFIG_R1 | DS620_REG_CONFIG_R0;
+
+       if (conf != new_conf)
+               i2c_smbus_write_word_data(client, DS620_REG_CONF,
+                                         swab16(new_conf));
+
+       /* start conversion */
+       i2c_smbus_write_byte(client, DS620_COM_START);
+}
+
+static struct ds620_data *ds620_update_client(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds620_data *data = i2c_get_clientdata(client);
+       struct ds620_data *ret = data;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+           || !data->valid) {
+               int i;
+               int res;
+
+               dev_dbg(&client->dev, "Starting ds620 update\n");
+
+               for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+                       res = ds620_read_temp(client,
+                                             DS620_REG_TEMP[i]);
+                       if (res < 0) {
+                               ret = ERR_PTR(res);
+                               goto abort;
+                       }
+
+                       data->temp[i] = res;
+               }
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+abort:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+                        char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct ds620_data *data = ds620_update_client(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", ((data->temp[attr->index] / 8) * 625) / 10);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+                       const char *buf, size_t count)
+{
+       int res;
+       long val;
+
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds620_data *data = i2c_get_clientdata(client);
+
+       res = strict_strtol(buf, 10, &val);
+
+       if (res)
+               return res;
+
+       val = (val * 10 / 625) * 8;
+
+       mutex_lock(&data->update_lock);
+       data->temp[attr->index] = val;
+       ds620_write_temp(client, DS620_REG_TEMP[attr->index],
+                        data->temp[attr->index]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+                         char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct ds620_data *data = ds620_update_client(dev);
+       struct i2c_client *client = to_i2c_client(dev);
+       u16 conf, new_conf;
+       int res;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       /* reset alarms if necessary */
+       res = i2c_smbus_read_word_data(client, DS620_REG_CONF);
+       if (res < 0)
+               return res;
+
+       conf = swab16(res);
+       new_conf = conf;
+       new_conf &= ~attr->index;
+       if (conf != new_conf) {
+               res = i2c_smbus_write_word_data(client, DS620_REG_CONF,
+                                               swab16(new_conf));
+               if (res < 0)
+                       return res;
+       }
+
+       return sprintf(buf, "%d\n", !!(conf & attr->index));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
+                         DS620_REG_CONFIG_TLF);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+                         DS620_REG_CONFIG_THF);
+
+static struct attribute *ds620_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group ds620_group = {
+       .attrs = ds620_attributes,
+};
+
+static int ds620_probe(struct i2c_client *client,
+                      const struct i2c_device_id *id)
+{
+       struct ds620_data *data;
+       int err;
+
+       data = kzalloc(sizeof(struct ds620_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* Initialize the DS620 chip */
+       ds620_init_client(client);
+
+       /* Register sysfs hooks */
+       err = sysfs_create_group(&client->dev.kobj, &ds620_group);
+       if (err)
+               goto exit_free;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_files;
+       }
+
+       dev_info(&client->dev, "temperature sensor found\n");
+
+       return 0;
+
+exit_remove_files:
+       sysfs_remove_group(&client->dev.kobj, &ds620_group);
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static int ds620_remove(struct i2c_client *client)
+{
+       struct ds620_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &ds620_group);
+
+       kfree(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id ds620_id[] = {
+       {"ds620", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ds620_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ds620_driver = {
+       .class = I2C_CLASS_HWMON,
+       .driver = {
+                  .name = "ds620",
+       },
+       .probe = ds620_probe,
+       .remove = ds620_remove,
+       .id_table = ds620_id,
+};
+
+static int __init ds620_init(void)
+{
+       return i2c_add_driver(&ds620_driver);
+}
+
+static void __exit ds620_exit(void)
+{
+       i2c_del_driver(&ds620_driver);
+}
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("DS620 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ds620_init);
+module_exit(ds620_exit);
index 525a00bd70b1c457c25a831e3017bf8d7b1afba4..92f949767ece5ccd6878896893177e34be63da2e 100644 (file)
@@ -28,6 +28,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -1309,7 +1311,7 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
 
        if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) {
                err = -ENOMEM;
-               printk(KERN_ERR DRVNAME ": Out of memory\n");
+               pr_err("Out of memory\n");
                goto exit;
        }
 
@@ -1451,7 +1453,7 @@ static int __init f71805f_device_add(unsigned short address,
        pdev = platform_device_alloc(DRVNAME, address);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit;
        }
 
@@ -1462,22 +1464,20 @@ static int __init f71805f_device_add(unsigned short address,
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device resource addition failed "
-                      "(%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
        err = platform_device_add_data(pdev, sio_data,
                                       sizeof(struct f71805f_sio_data));
        if (err) {
-               printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+               pr_err("Platform data allocation failed\n");
                goto exit_device_put;
        }
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
@@ -1516,30 +1516,27 @@ static int __init f71805f_find(int sioaddr, unsigned short *address,
                sio_data->fnsel1 = superio_inb(sioaddr, SIO_REG_FNSEL1);
                break;
        default:
-               printk(KERN_INFO DRVNAME ": Unsupported Fintek device, "
-                      "skipping\n");
+               pr_info("Unsupported Fintek device, skipping\n");
                goto exit;
        }
 
        superio_select(sioaddr, F71805F_LD_HWM);
        if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
-               printk(KERN_WARNING DRVNAME ": Device not activated, "
-                      "skipping\n");
+               pr_warn("Device not activated, skipping\n");
                goto exit;
        }
 
        *address = superio_inw(sioaddr, SIO_REG_ADDR);
        if (*address == 0) {
-               printk(KERN_WARNING DRVNAME ": Base address not set, "
-                      "skipping\n");
+               pr_warn("Base address not set, skipping\n");
                goto exit;
        }
        *address &= ~(REGION_LENGTH - 1);       /* Ignore 3 LSB */
 
        err = 0;
-       printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %u\n",
-              names[sio_data->kind], *address,
-              superio_inb(sioaddr, SIO_REG_DEVREV));
+       pr_info("Found %s chip at %#x, revision %u\n",
+               names[sio_data->kind], *address,
+               superio_inb(sioaddr, SIO_REG_DEVREV));
 
 exit:
        superio_exit(sioaddr);
index 75afb3b0e0763c184a1b22cdc163ef32d10d2969..3f49dd376f023e1e6d4a281bc84ae9f05c59288a 100644 (file)
@@ -18,6 +18,8 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -865,8 +867,7 @@ static inline int superio_enter(int base)
 {
        /* Don't step on other drivers' I/O space by accident */
        if (!request_muxed_region(base, 2, DRVNAME)) {
-               printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
-                               base);
+               pr_err("I/O address 0x%04x already in use\n", base);
                return -EBUSY;
        }
 
@@ -2192,7 +2193,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
 
        devid = superio_inw(sioaddr, SIO_REG_MANID);
        if (devid != SIO_FINTEK_ID) {
-               pr_debug(DRVNAME ": Not a Fintek device\n");
+               pr_debug("Not a Fintek device\n");
                err = -ENODEV;
                goto exit;
        }
@@ -2215,8 +2216,8 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
                sio_data->type = f8000;
                break;
        default:
-               printk(KERN_INFO DRVNAME ": Unsupported Fintek device: %04x\n",
-                      (unsigned int)devid);
+               pr_info("Unsupported Fintek device: %04x\n",
+                       (unsigned int)devid);
                err = -ENODEV;
                goto exit;
        }
@@ -2227,21 +2228,21 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
                superio_select(sioaddr, SIO_F71882FG_LD_HWM);
 
        if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
-               printk(KERN_WARNING DRVNAME ": Device not activated\n");
+               pr_warn("Device not activated\n");
                err = -ENODEV;
                goto exit;
        }
 
        *address = superio_inw(sioaddr, SIO_REG_ADDR);
        if (*address == 0) {
-               printk(KERN_WARNING DRVNAME ": Base address not set\n");
+               pr_warn("Base address not set\n");
                err = -ENODEV;
                goto exit;
        }
        *address &= ~(REGION_LENGTH - 1);       /* Ignore 3 LSB */
 
        err = 0;
-       printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
+       pr_info("Found %s chip at %#x, revision %d\n",
                f71882fg_names[sio_data->type], (unsigned int)*address,
                (int)superio_inb(sioaddr, SIO_REG_DEVREV));
 exit:
@@ -2270,20 +2271,20 @@ static int __init f71882fg_device_add(unsigned short address,
 
        err = platform_device_add_resources(f71882fg_pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
+               pr_err("Device resource addition failed\n");
                goto exit_device_put;
        }
 
        err = platform_device_add_data(f71882fg_pdev, sio_data,
                                       sizeof(struct f71882fg_sio_data));
        if (err) {
-               printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+               pr_err("Platform data allocation failed\n");
                goto exit_device_put;
        }
 
        err = platform_device_add(f71882fg_pdev);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device addition failed\n");
+               pr_err("Device addition failed\n");
                goto exit_device_put;
        }
 
index a56a78412fcba4f9e8d42887cd40382d4418bd2d..3d21fa2b97cd1d922119b17ea6a4780e89fc8a63 100644 (file)
@@ -20,6 +20,8 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
@@ -147,7 +149,7 @@ int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
 static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
 {
        lis3_dev.ac = *((union axis_conversion *)dmi->driver_data);
-       printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
+       pr_info("hardware type %s found\n", dmi->ident);
 
        return 1;
 }
@@ -303,11 +305,10 @@ static int lis3lv02d_add(struct acpi_device *device)
 
        /* If possible use a "standard" axes order */
        if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) {
-               printk(KERN_INFO DRIVER_NAME ": Using custom axes %d,%d,%d\n",
-                      lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
+               pr_info("Using custom axes %d,%d,%d\n",
+                       lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
        } else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
-               printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
-                                "using default axes configuration\n");
+               pr_info("laptop model unknown, using default axes configuration\n");
                lis3_dev.ac = lis3lv02d_axis_normal;
        }
 
@@ -385,7 +386,7 @@ static int __init lis3lv02d_init_module(void)
        if (ret < 0)
                return ret;
 
-       printk(KERN_INFO DRIVER_NAME " driver loaded.\n");
+       pr_info("driver loaded\n");
 
        return 0;
 }
index 2b2ca1694f95e5e466e6211ef5f3230f2fc0fc02..2582bfef6ccb8a1accc4bad5a660dd621eba7fdb 100644 (file)
@@ -22,6 +22,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/hwmon-vid.h>
@@ -146,8 +148,8 @@ int vid_from_reg(int val, u8 vrm)
                return(val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000);
        default:                /* report 0 for unknown */
                if (vrm)
-                       printk(KERN_WARNING "hwmon-vid: Requested unsupported "
-                              "VRM version (%u)\n", (unsigned int)vrm);
+                       pr_warn("Requested unsupported VRM version (%u)\n",
+                               (unsigned int)vrm);
                return 0;
        }
 }
@@ -246,8 +248,7 @@ u8 vid_which_vrm(void)
        }
        vrm_ret = find_vrm(eff_family, eff_model, eff_stepping, c->x86_vendor);
        if (vrm_ret == 0)
-               printk(KERN_INFO "hwmon-vid: Unknown VRM version of your "
-                      "x86 CPU\n");
+               pr_info("Unknown VRM version of your x86 CPU\n");
        return vrm_ret;
 }
 
@@ -255,7 +256,7 @@ u8 vid_which_vrm(void)
 #else
 u8 vid_which_vrm(void)
 {
-       printk(KERN_INFO "hwmon-vid: Unknown VRM version of your CPU\n");
+       pr_info("Unknown VRM version of your CPU\n");
        return 0;
 }
 #endif
index 29ea6753f3bbe54592168dcaa1db07b1a2dbab3d..a61e7815a2a9153f7ad82e8dc2ff49273763c19a 100644 (file)
@@ -10,6 +10,8 @@
     the Free Software Foundation; version 2 of the License.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -119,7 +121,7 @@ static int __init hwmon_init(void)
 
        hwmon_class = class_create(THIS_MODULE, "hwmon");
        if (IS_ERR(hwmon_class)) {
-               printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n");
+               pr_err("couldn't create sysfs class\n");
                return PTR_ERR(hwmon_class);
        }
        return 0;
index eaee546af19a1c519758783ee66217a1d8bae46d..bc6e2ab3a361d539befcc2055ebcb5a1c119f5a9 100644 (file)
@@ -20,6 +20,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/ipmi.h>
 #include <linux/module.h>
 #include <linux/hwmon.h>
@@ -1090,7 +1092,7 @@ static int __init aem_init(void)
 
        res = driver_register(&aem_driver.driver);
        if (res) {
-               printk(KERN_ERR "Can't register aem driver\n");
+               pr_err("Can't register aem driver\n");
                return res;
        }
 
index 0cee73a6124e346238bb9bbdded94f0c0d167f59..1b674b7d4584ee74b1f8399f87ea9d5e62c22dfc 100644 (file)
@@ -20,6 +20,8 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
@@ -860,8 +862,7 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
                                        (p->irq_flags2 & IRQF_TRIGGER_MASK),
                                        DRIVER_NAME, &lis3_dev);
                if (err < 0)
-                       printk(KERN_ERR DRIVER_NAME
-                               "No second IRQ. Limited functionality\n");
+                       pr_err("No second IRQ. Limited functionality\n");
        }
 }
 
@@ -879,7 +880,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
 
        switch (dev->whoami) {
        case WAI_12B:
-               printk(KERN_INFO DRIVER_NAME ": 12 bits sensor found\n");
+               pr_info("12 bits sensor found\n");
                dev->read_data = lis3lv02d_read_12;
                dev->mdps_max_val = 2048;
                dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
@@ -890,7 +891,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                dev->regs_size = ARRAY_SIZE(lis3_wai12_regs);
                break;
        case WAI_8B:
-               printk(KERN_INFO DRIVER_NAME ": 8 bits sensor found\n");
+               pr_info("8 bits sensor found\n");
                dev->read_data = lis3lv02d_read_8;
                dev->mdps_max_val = 128;
                dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
@@ -901,7 +902,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                dev->regs_size = ARRAY_SIZE(lis3_wai8_regs);
                break;
        case WAI_3DC:
-               printk(KERN_INFO DRIVER_NAME ": 8 bits 3DC sensor found\n");
+               pr_info("8 bits 3DC sensor found\n");
                dev->read_data = lis3lv02d_read_8;
                dev->mdps_max_val = 128;
                dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
@@ -910,8 +911,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                dev->scale = LIS3_SENSITIVITY_8B;
                break;
        default:
-               printk(KERN_ERR DRIVER_NAME
-                       ": unknown sensor type 0x%X\n", dev->whoami);
+               pr_err("unknown sensor type 0x%X\n", dev->whoami);
                return -EINVAL;
        }
 
@@ -935,7 +935,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
        }
 
        if (lis3lv02d_joystick_enable())
-               printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
+               pr_err("joystick initialization failed\n");
 
        /* passing in platform specific data is purely optional and only
         * used by the SPI transport layer at the moment */
@@ -957,8 +957,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
 
        /* bail if we did not get an IRQ from the bus layer */
        if (!dev->irq) {
-               printk(KERN_ERR DRIVER_NAME
-                       ": No IRQ. Disabling /dev/freefall\n");
+               pr_err("No IRQ. Disabling /dev/freefall\n");
                goto out;
        }
 
@@ -985,12 +984,12 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                                DRIVER_NAME, &lis3_dev);
 
        if (err < 0) {
-               printk(KERN_ERR DRIVER_NAME "Cannot get IRQ\n");
+               pr_err("Cannot get IRQ\n");
                goto out;
        }
 
        if (misc_register(&lis3lv02d_misc_device))
-               printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
+               pr_err("misc_register failed\n");
 out:
        return 0;
 }
index fd108cfc05c7c8cad39b960b484e377ded238b5a..3b84fb5030535d3e16d60e164a68dd0fb8ef8a4f 100644 (file)
@@ -24,6 +24,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -67,8 +69,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
         */
        status = spi_write_then_read(spi, NULL, 0, &rxbuf[0], 2);
        if (status < 0) {
-               printk(KERN_WARNING
-               "spi_write_then_read failed with status %d\n", status);
+               pr_warn("spi_write_then_read failed with status %d\n", status);
                goto out;
        }
        raw = (rxbuf[0] << 8) + rxbuf[1];
index 4546d82f024a4c2acacf3c6d93e0ad2a4a4bf3e6..1a6dfb6df1e7ff121ce4903ab80f1b2e57ba2ef1 100644 (file)
@@ -1,13 +1,9 @@
 /*
- * lm95241.c - Part of lm_sensors, Linux kernel modules for hardware
- *             monitoring
- * Copyright (C) 2008 Davide Rizzo <elpa-rizzo@gmail.com>
+ * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
  *
- * Based on the max1619 driver. The LM95241 is a sensor chip made by National
- *   Semiconductors.
- * It reports up to three temperatures (its own plus up to
- * two external ones). Complete datasheet can be
- * obtained from National's website at:
+ * The LM95241 is a sensor chip made by National Semiconductors.
+ * It reports up to three temperatures (its own plus up to two external ones).
+ * Complete datasheet can be obtained from National's website at:
  *   http://www.national.com/ds.cgi/LM/LM95241.pdf
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
 
+#define DEVNAME "lm95241"
+
 static const unsigned short normal_i2c[] = {
-       0x19, 0x2a, 0x2b, I2C_CLIENT_END};
+       0x19, 0x2a, 0x2b, I2C_CLIENT_END };
 
 /* LM95241 registers */
 #define LM95241_REG_R_MAN_ID           0xFE
@@ -46,7 +44,7 @@ static const unsigned short normal_i2c[] = {
 #define LM95241_REG_RW_CONFIG          0x03
 #define LM95241_REG_RW_REM_FILTER      0x06
 #define LM95241_REG_RW_TRUTHERM                0x07
-#define LM95241_REG_W_ONE_SHOT         0x0F
+#define LM95241_REG_W_ONE_SHOT         0x0F
 #define LM95241_REG_R_LOCAL_TEMPH      0x10
 #define LM95241_REG_R_REMOTE1_TEMPH    0x11
 #define LM95241_REG_R_REMOTE2_TEMPH    0x12
@@ -79,235 +77,246 @@ static const unsigned short normal_i2c[] = {
 #define MANUFACTURER_ID 0x01
 #define DEFAULT_REVISION 0xA4
 
-/* Conversions and various macros */
-#define TEMP_FROM_REG(val_h, val_l) (((val_h) & 0x80 ? (val_h) - 0x100 : \
-    (val_h)) * 1000 + (val_l) * 1000 / 256)
-
-/* Functions declaration */
-static void lm95241_init_client(struct i2c_client *client);
-static struct lm95241_data *lm95241_update_device(struct device *dev);
+static const u8 lm95241_reg_address[] = {
+       LM95241_REG_R_LOCAL_TEMPH,
+       LM95241_REG_R_LOCAL_TEMPL,
+       LM95241_REG_R_REMOTE1_TEMPH,
+       LM95241_REG_R_REMOTE1_TEMPL,
+       LM95241_REG_R_REMOTE2_TEMPH,
+       LM95241_REG_R_REMOTE2_TEMPL
+};
 
 /* Client data (each client gets its own) */
 struct lm95241_data {
        struct device *hwmon_dev;
        struct mutex update_lock;
-       unsigned long last_updated, interval; /* in jiffies */
-       char valid; /* zero until following fields are valid */
+       unsigned long last_updated, interval;   /* in jiffies */
+       char valid;             /* zero until following fields are valid */
        /* registers values */
-       u8 local_h, local_l; /* local */
-       u8 remote1_h, remote1_l; /* remote1 */
-       u8 remote2_h, remote2_l; /* remote2 */
+       u8 temp[ARRAY_SIZE(lm95241_reg_address)];
        u8 config, model, trutherm;
 };
 
+/* Conversions */
+static int TempFromReg(u8 val_h, u8 val_l)
+{
+       if (val_h & 0x80)
+               return val_h - 0x100;
+       return val_h * 1000 + val_l * 1000 / 256;
+}
+
+static struct lm95241_data *lm95241_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + data->interval) ||
+           !data->valid) {
+               int i;
+
+               dev_dbg(&client->dev, "Updating lm95241 data.\n");
+               for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++)
+                       data->temp[i]
+                         = i2c_smbus_read_byte_data(client,
+                                                    lm95241_reg_address[i]);
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
 /* Sysfs stuff */
-#define show_temp(value) \
-static ssize_t show_##value(struct device *dev, \
-    struct device_attribute *attr, char *buf) \
-{ \
-       struct lm95241_data *data = lm95241_update_device(dev); \
-       snprintf(buf, PAGE_SIZE - 1, "%d\n", \
-               TEMP_FROM_REG(data->value##_h, data->value##_l)); \
-       return strlen(buf); \
+static ssize_t show_input(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct lm95241_data *data = lm95241_update_device(dev);
+
+       return snprintf(buf, PAGE_SIZE - 1, "%d\n",
+               TempFromReg(data->temp[to_sensor_dev_attr(attr)->index],
+                           data->temp[to_sensor_dev_attr(attr)->index + 1]));
 }
-show_temp(local);
-show_temp(remote1);
-show_temp(remote2);
 
-static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
-       struct lm95241_data *data = lm95241_update_device(dev);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
 
-       snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->interval / HZ);
-       return strlen(buf);
+       return snprintf(buf, PAGE_SIZE - 1,
+               data->model & to_sensor_dev_attr(attr)->index ? "1\n" : "2\n");
 }
 
-static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct lm95241_data *data = i2c_get_clientdata(client);
        unsigned long val;
+       int shift;
+       u8 mask = to_sensor_dev_attr(attr)->index;
 
        if (strict_strtoul(buf, 10, &val) < 0)
                return -EINVAL;
+       if (val != 1 && val != 2)
+               return -EINVAL;
 
-       data->interval = val * HZ / 1000;
+       shift = mask == R1MS_MASK ? TT1_SHIFT : TT2_SHIFT;
+
+       mutex_lock(&data->update_lock);
+
+       data->trutherm &= ~(TT_MASK << shift);
+       if (val == 1) {
+               data->model |= mask;
+               data->trutherm |= (TT_ON << shift);
+       } else {
+               data->model &= ~mask;
+               data->trutherm |= (TT_OFF << shift);
+       }
+       data->valid = 0;
+
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
+                                 data->model);
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
+                                 data->trutherm);
+
+       mutex_unlock(&data->update_lock);
 
        return count;
 }
 
-#define show_type(flag) \
-static ssize_t show_type##flag(struct device *dev, \
-                                  struct device_attribute *attr, char *buf) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct lm95241_data *data = i2c_get_clientdata(client); \
-\
-       snprintf(buf, PAGE_SIZE - 1, \
-               data->model & R##flag##MS_MASK ? "1\n" : "2\n"); \
-       return strlen(buf); \
+static ssize_t show_min(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
+
+       return snprintf(buf, PAGE_SIZE - 1,
+                       data->config & to_sensor_dev_attr(attr)->index ?
+                       "-127000\n" : "0\n");
 }
-show_type(1);
-show_type(2);
-
-#define show_min(flag) \
-static ssize_t show_min##flag(struct device *dev, \
-    struct device_attribute *attr, char *buf) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct lm95241_data *data = i2c_get_clientdata(client); \
-\
-       snprintf(buf, PAGE_SIZE - 1, \
-               data->config & R##flag##DF_MASK ?       \
-               "-127000\n" : "0\n"); \
-       return strlen(buf); \
+
+static ssize_t set_min(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
+       long val;
+
+       if (strict_strtol(buf, 10, &val) < 0)
+               return -EINVAL;
+       if (val < -128000)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+
+       if (val < 0)
+               data->config |= to_sensor_dev_attr(attr)->index;
+       else
+               data->config &= ~to_sensor_dev_attr(attr)->index;
+       data->valid = 0;
+
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
 }
-show_min(1);
-show_min(2);
-
-#define show_max(flag) \
-static ssize_t show_max##flag(struct device *dev, \
-    struct device_attribute *attr, char *buf) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct lm95241_data *data = i2c_get_clientdata(client); \
-\
-       snprintf(buf, PAGE_SIZE - 1, \
-               data->config & R##flag##DF_MASK ? \
-               "127000\n" : "255000\n"); \
-       return strlen(buf); \
+
+static ssize_t show_max(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
+
+       return snprintf(buf, PAGE_SIZE - 1,
+                       data->config & to_sensor_dev_attr(attr)->index ?
+                       "127000\n" : "255000\n");
 }
-show_max(1);
-show_max(2);
-
-#define set_type(flag) \
-static ssize_t set_type##flag(struct device *dev, \
-                                 struct device_attribute *attr, \
-                                 const char *buf, size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct lm95241_data *data = i2c_get_clientdata(client); \
-\
-       long val; \
-\
-       if (strict_strtol(buf, 10, &val) < 0) \
-               return -EINVAL; \
-\
-       if ((val == 1) || (val == 2)) { \
-\
-               mutex_lock(&data->update_lock); \
-\
-               data->trutherm &= ~(TT_MASK << TT##flag##_SHIFT); \
-               if (val == 1) { \
-                       data->model |= R##flag##MS_MASK; \
-                       data->trutherm |= (TT_ON << TT##flag##_SHIFT); \
-               } \
-               else { \
-                       data->model &= ~R##flag##MS_MASK; \
-                       data->trutherm |= (TT_OFF << TT##flag##_SHIFT); \
-               } \
-\
-               data->valid = 0; \
-\
-               i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, \
-                                         data->model); \
-               i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, \
-                                         data->trutherm); \
-\
-               mutex_unlock(&data->update_lock); \
-\
-       } \
-       return count; \
+
+static ssize_t set_max(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
+       long val;
+
+       if (strict_strtol(buf, 10, &val) < 0)
+               return -EINVAL;
+       if (val >= 256000)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+
+       if (val <= 127000)
+               data->config |= to_sensor_dev_attr(attr)->index;
+       else
+               data->config &= ~to_sensor_dev_attr(attr)->index;
+       data->valid = 0;
+
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
 }
-set_type(1);
-set_type(2);
-
-#define set_min(flag) \
-static ssize_t set_min##flag(struct device *dev, \
-       struct device_attribute *devattr, const char *buf, size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct lm95241_data *data = i2c_get_clientdata(client); \
-\
-       long val; \
-\
-       if (strict_strtol(buf, 10, &val) < 0) \
-               return -EINVAL;\
-\
-       mutex_lock(&data->update_lock); \
-\
-       if (val < 0) \
-               data->config |= R##flag##DF_MASK; \
-       else \
-               data->config &= ~R##flag##DF_MASK; \
-\
-       data->valid = 0; \
-\
-       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \
-               data->config); \
-\
-       mutex_unlock(&data->update_lock); \
-\
-       return count; \
+
+static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct lm95241_data *data = lm95241_update_device(dev);
+
+       return snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->interval
+                       / HZ);
 }
-set_min(1);
-set_min(2);
-
-#define set_max(flag) \
-static ssize_t set_max##flag(struct device *dev, \
-       struct device_attribute *devattr, const char *buf, size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct lm95241_data *data = i2c_get_clientdata(client); \
-\
-       long val; \
-\
-       if (strict_strtol(buf, 10, &val) < 0) \
-               return -EINVAL; \
-\
-       mutex_lock(&data->update_lock); \
-\
-       if (val <= 127000) \
-               data->config |= R##flag##DF_MASK; \
-       else \
-               data->config &= ~R##flag##DF_MASK; \
-\
-       data->valid = 0; \
-\
-       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \
-               data->config); \
-\
-       mutex_unlock(&data->update_lock); \
-\
-       return count; \
+
+static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       data->interval = val * HZ / 1000;
+
+       return count;
 }
-set_max(1);
-set_max(2);
-
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_local, NULL);
-static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote1, NULL);
-static DEVICE_ATTR(temp3_input, S_IRUGO, show_remote2, NULL);
-static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type1, set_type1);
-static DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type2, set_type2);
-static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min1, set_min1);
-static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2);
-static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1);
-static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type,
+                         R1MS_MASK);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type, set_type,
+                         R2MS_MASK);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min, set_min,
+                         R1DF_MASK);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min, set_min,
+                         R2DF_MASK);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max, set_max,
+                         R1DF_MASK);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max,
+                         R2DF_MASK);
 static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
                   set_interval);
 
 static struct attribute *lm95241_attributes[] = {
-       &dev_attr_temp1_input.attr,
-       &dev_attr_temp2_input.attr,
-       &dev_attr_temp3_input.attr,
-       &dev_attr_temp2_type.attr,
-       &dev_attr_temp3_type.attr,
-       &dev_attr_temp2_min.attr,
-       &dev_attr_temp3_min.attr,
-       &dev_attr_temp2_max.attr,
-       &dev_attr_temp3_max.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_type.dev_attr.attr,
+       &sensor_dev_attr_temp3_type.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
        &dev_attr_update_interval.attr,
        NULL
 };
@@ -329,9 +338,9 @@ static int lm95241_detect(struct i2c_client *new_client,
 
        if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
             == MANUFACTURER_ID)
-        && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
-            >= DEFAULT_REVISION)) {
-               name = "lm95241";
+           && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
+               >= DEFAULT_REVISION)) {
+               name = DEVNAME;
        } else {
                dev_dbg(&adapter->dev, "LM95241 detection failed at 0x%02x\n",
                        address);
@@ -343,6 +352,25 @@ static int lm95241_detect(struct i2c_client *new_client,
        return 0;
 }
 
+static void lm95241_init_client(struct i2c_client *client)
+{
+       struct lm95241_data *data = i2c_get_clientdata(client);
+
+       data->interval = HZ;    /* 1 sec default */
+       data->valid = 0;
+       data->config = CFG_CR0076;
+       data->model = 0;
+       data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
+
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER,
+                                 R1FE_MASK | R2FE_MASK);
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
+                                 data->trutherm);
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
+                                 data->model);
+}
+
 static int lm95241_probe(struct i2c_client *new_client,
                         const struct i2c_device_id *id)
 {
@@ -382,26 +410,6 @@ exit:
        return err;
 }
 
-static void lm95241_init_client(struct i2c_client *client)
-{
-       struct lm95241_data *data = i2c_get_clientdata(client);
-
-       data->interval = HZ;    /* 1 sec default */
-       data->valid = 0;
-       data->config = CFG_CR0076;
-       data->model = 0;
-       data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
-
-       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG,
-                                 data->config);
-       i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER,
-                                 R1FE_MASK | R2FE_MASK);
-       i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
-                                 data->trutherm);
-       i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
-                                 data->model);
-}
-
 static int lm95241_remove(struct i2c_client *client)
 {
        struct lm95241_data *data = i2c_get_clientdata(client);
@@ -413,46 +421,9 @@ static int lm95241_remove(struct i2c_client *client)
        return 0;
 }
 
-static struct lm95241_data *lm95241_update_device(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95241_data *data = i2c_get_clientdata(client);
-
-       mutex_lock(&data->update_lock);
-
-       if (time_after(jiffies, data->last_updated + data->interval) ||
-           !data->valid) {
-               dev_dbg(&client->dev, "Updating lm95241 data.\n");
-               data->local_h =
-                       i2c_smbus_read_byte_data(client,
-                                                LM95241_REG_R_LOCAL_TEMPH);
-               data->local_l =
-                       i2c_smbus_read_byte_data(client,
-                                                LM95241_REG_R_LOCAL_TEMPL);
-               data->remote1_h =
-                       i2c_smbus_read_byte_data(client,
-                                                LM95241_REG_R_REMOTE1_TEMPH);
-               data->remote1_l =
-                       i2c_smbus_read_byte_data(client,
-                                                LM95241_REG_R_REMOTE1_TEMPL);
-               data->remote2_h =
-                       i2c_smbus_read_byte_data(client,
-                                                LM95241_REG_R_REMOTE2_TEMPH);
-               data->remote2_l =
-                       i2c_smbus_read_byte_data(client,
-                                                LM95241_REG_R_REMOTE2_TEMPL);
-               data->last_updated = jiffies;
-               data->valid = 1;
-       }
-
-       mutex_unlock(&data->update_lock);
-
-       return data;
-}
-
 /* Driver data (common to all clients) */
 static const struct i2c_device_id lm95241_id[] = {
-       { "lm95241", 0 },
+       { DEVNAME, 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm95241_id);
@@ -460,7 +431,7 @@ MODULE_DEVICE_TABLE(i2c, lm95241_id);
 static struct i2c_driver lm95241_driver = {
        .class          = I2C_CLASS_HWMON,
        .driver = {
-               .name   = "lm95241",
+               .name   = DEVNAME,
        },
        .probe          = lm95241_probe,
        .remove         = lm95241_remove,
@@ -479,7 +450,7 @@ static void __exit sensors_lm95241_exit(void)
        i2c_del_driver(&lm95241_driver);
 }
 
-MODULE_AUTHOR("Davide Rizzo <elpa-rizzo@gmail.com>");
+MODULE_AUTHOR("Davide Rizzo <elpa.rizzo@gmail.com>");
 MODULE_DESCRIPTION("LM95241 sensor driver");
 MODULE_LICENSE("GPL");
 
index dc7259d698120d895aedc8b13d9c73c564c0e00b..731b09af76b960b676e55b983dc8ff350b5d0380 100644 (file)
@@ -18,6 +18,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -290,8 +292,7 @@ static struct i2c_driver pcf8591_driver = {
 static int __init pcf8591_init(void)
 {
        if (input_mode < 0 || input_mode > 3) {
-               printk(KERN_WARNING "pcf8591: invalid input_mode (%d)\n",
-                      input_mode);
+               pr_warn("invalid input_mode (%d)\n", input_mode);
                input_mode = 0;
        }
        return i2c_add_driver(&pcf8591_driver);
index 0798210590bc01f19136b76ef073e16f122ea11f..21c817d98123f7d8fe6e96efcb499785ef931ddb 100644 (file)
@@ -20,6 +20,8 @@
  * 02110-1301 USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -303,7 +305,7 @@ static int __cpuinit pkgtemp_device_add(unsigned int cpu)
        pdev = platform_device_alloc(DRVNAME, cpu);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit;
        }
 
@@ -315,8 +317,7 @@ static int __cpuinit pkgtemp_device_add(unsigned int cpu)
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_free;
        }
 
diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
new file mode 100644 (file)
index 0000000..1c8c981
--- /dev/null
@@ -0,0 +1,307 @@
+/* Sensirion SHT21 humidity and temperature sensor driver
+ *
+ * Copyright (C) 2010 Urs Fleisch <urs.fleisch@sensirion.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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Data sheet available (5/2010) at
+ * http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+
+/* I2C command bytes */
+#define SHT21_TRIG_T_MEASUREMENT_HM  0xe3
+#define SHT21_TRIG_RH_MEASUREMENT_HM 0xe5
+
+/**
+ * struct sht21 - SHT21 device specific data
+ * @hwmon_dev: device registered with hwmon
+ * @lock: mutex to protect measurement values
+ * @valid: only 0 before first measurement is taken
+ * @last_update: time of last update (jiffies)
+ * @temperature: cached temperature measurement value
+ * @humidity: cached humidity measurement value
+ */
+struct sht21 {
+       struct device *hwmon_dev;
+       struct mutex lock;
+       char valid;
+       unsigned long last_update;
+       int temperature;
+       int humidity;
+};
+
+/**
+ * sht21_temp_ticks_to_millicelsius() - convert raw temperature ticks to
+ * milli celsius
+ * @ticks: temperature ticks value received from sensor
+ */
+static inline int sht21_temp_ticks_to_millicelsius(int ticks)
+{
+       ticks &= ~0x0003; /* clear status bits */
+       /*
+        * Formula T = -46.85 + 175.72 * ST / 2^16 from data sheet 6.2,
+        * optimized for integer fixed point (3 digits) arithmetic
+        */
+       return ((21965 * ticks) >> 13) - 46850;
+}
+
+/**
+ * sht21_rh_ticks_to_per_cent_mille() - convert raw humidity ticks to
+ * one-thousandths of a percent relative humidity
+ * @ticks: humidity ticks value received from sensor
+ */
+static inline int sht21_rh_ticks_to_per_cent_mille(int ticks)
+{
+       ticks &= ~0x0003; /* clear status bits */
+       /*
+        * Formula RH = -6 + 125 * SRH / 2^16 from data sheet 6.1,
+        * optimized for integer fixed point (3 digits) arithmetic
+        */
+       return ((15625 * ticks) >> 13) - 6000;
+}
+
+/**
+ * sht21_read_word_data() - read word from register
+ * @client: I2C client device
+ * @reg: I2C command byte
+ *
+ * Returns value, negative errno on error.
+ */
+static inline int sht21_read_word_data(struct i2c_client *client, u8 reg)
+{
+       int ret = i2c_smbus_read_word_data(client, reg);
+       if (ret < 0)
+               return ret;
+       /*
+        * SMBus specifies low byte first, but the SHT21 returns MSB
+        * first, so we have to swab16 the values
+        */
+       return swab16(ret);
+}
+
+/**
+ * sht21_update_measurements() - get updated measurements from device
+ * @client: I2C client device
+ *
+ * Returns 0 on success, else negative errno.
+ */
+static int sht21_update_measurements(struct i2c_client *client)
+{
+       int ret = 0;
+       struct sht21 *sht21 = i2c_get_clientdata(client);
+
+       mutex_lock(&sht21->lock);
+       /*
+        * Data sheet 2.4:
+        * SHT2x should not be active for more than 10% of the time - e.g.
+        * maximum two measurements per second at 12bit accuracy shall be made.
+        */
+       if (time_after(jiffies, sht21->last_update + HZ / 2) || !sht21->valid) {
+               ret = sht21_read_word_data(client, SHT21_TRIG_T_MEASUREMENT_HM);
+               if (ret < 0)
+                       goto out;
+               sht21->temperature = sht21_temp_ticks_to_millicelsius(ret);
+               ret = sht21_read_word_data(client,
+                                       SHT21_TRIG_RH_MEASUREMENT_HM);
+               if (ret < 0)
+                       goto out;
+               sht21->humidity = sht21_rh_ticks_to_per_cent_mille(ret);
+               sht21->last_update = jiffies;
+               sht21->valid = 1;
+       }
+out:
+       mutex_unlock(&sht21->lock);
+
+       return ret >= 0 ? 0 : ret;
+}
+
+/**
+ * sht21_show_temperature() - show temperature measurement value in sysfs
+ * @dev: device
+ * @attr: device attribute
+ * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
+ *
+ * Will be called on read access to temp1_input sysfs attribute.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
+static ssize_t sht21_show_temperature(struct device *dev,
+       struct device_attribute *attr,
+       char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct sht21 *sht21 = i2c_get_clientdata(client);
+       int ret = sht21_update_measurements(client);
+       if (ret < 0)
+               return ret;
+       return sprintf(buf, "%d\n", sht21->temperature);
+}
+
+/**
+ * sht21_show_humidity() - show humidity measurement value in sysfs
+ * @dev: device
+ * @attr: device attribute
+ * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
+ *
+ * Will be called on read access to humidity1_input sysfs attribute.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
+static ssize_t sht21_show_humidity(struct device *dev,
+       struct device_attribute *attr,
+       char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct sht21 *sht21 = i2c_get_clientdata(client);
+       int ret = sht21_update_measurements(client);
+       if (ret < 0)
+               return ret;
+       return sprintf(buf, "%d\n", sht21->humidity);
+}
+
+/* sysfs attributes */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sht21_show_temperature,
+       NULL, 0);
+static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, sht21_show_humidity,
+       NULL, 0);
+
+static struct attribute *sht21_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_humidity1_input.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group sht21_attr_group = {
+       .attrs = sht21_attributes,
+};
+
+/**
+ * sht21_probe() - probe device
+ * @client: I2C client device
+ * @id: device ID
+ *
+ * Called by the I2C core when an entry in the ID table matches a
+ * device's name.
+ * Returns 0 on success.
+ */
+static int __devinit sht21_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       struct sht21 *sht21;
+       int err;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_err(&client->dev,
+                       "adapter does not support SMBus word transactions\n");
+               return -ENODEV;
+       }
+
+       sht21 = kzalloc(sizeof(*sht21), GFP_KERNEL);
+       if (!sht21) {
+               dev_dbg(&client->dev, "kzalloc failed\n");
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(client, sht21);
+
+       mutex_init(&sht21->lock);
+
+       err = sysfs_create_group(&client->dev.kobj, &sht21_attr_group);
+       if (err) {
+               dev_dbg(&client->dev, "could not create sysfs files\n");
+               goto fail_free;
+       }
+       sht21->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(sht21->hwmon_dev)) {
+               dev_dbg(&client->dev, "unable to register hwmon device\n");
+               err = PTR_ERR(sht21->hwmon_dev);
+               goto fail_remove_sysfs;
+       }
+
+       dev_info(&client->dev, "initialized\n");
+
+       return 0;
+
+fail_remove_sysfs:
+       sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
+fail_free:
+       kfree(sht21);
+
+       return err;
+}
+
+/**
+ * sht21_remove() - remove device
+ * @client: I2C client device
+ */
+static int __devexit sht21_remove(struct i2c_client *client)
+{
+       struct sht21 *sht21 = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(sht21->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
+       kfree(sht21);
+
+       return 0;
+}
+
+/* Device ID table */
+static const struct i2c_device_id sht21_id[] = {
+       { "sht21", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, sht21_id);
+
+static struct i2c_driver sht21_driver = {
+       .driver.name = "sht21",
+       .probe       = sht21_probe,
+       .remove      = __devexit_p(sht21_remove),
+       .id_table    = sht21_id,
+};
+
+/**
+ * sht21_init() - initialize driver
+ *
+ * Called when kernel is booted or module is inserted.
+ * Returns 0 on success.
+ */
+static int __init sht21_init(void)
+{
+       return i2c_add_driver(&sht21_driver);
+}
+module_init(sht21_init);
+
+/**
+ * sht21_init() - clean up driver
+ *
+ * Called when module is removed.
+ */
+static void __exit sht21_exit(void)
+{
+       i2c_del_driver(&sht21_driver);
+}
+module_exit(sht21_exit);
+
+MODULE_AUTHOR("Urs Fleisch <urs.fleisch@sensirion.com>");
+MODULE_DESCRIPTION("Sensirion SHT21 humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
index 79c2931e30085632b594bf67bd5ff8db37bb10a1..47d7ce9af8fb83121fafdb3b5c3ba8a3454740a5 100644 (file)
@@ -50,6 +50,8 @@
         735            0008            0735
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
@@ -735,21 +737,19 @@ static int __devinit sis5595_device_add(unsigned short address)
        pdev = platform_device_alloc("sis5595", address);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR "sis5595: Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit;
        }
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR "sis5595: Device resource addition failed "
-                      "(%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR "sis5595: Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
index f46d936c12da890745de4ce11811a767fed78490..9fb7516e6f451284419559fdf4faf3e8fffbeaf9 100644 (file)
@@ -26,6 +26,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
@@ -311,21 +313,19 @@ static int __init smsc47b397_device_add(unsigned short address)
        pdev = platform_device_alloc(DRVNAME, address);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit;
        }
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device resource addition failed "
-                      "(%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
@@ -367,8 +367,7 @@ static int __init smsc47b397_find(unsigned short *addr)
        *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8)
                 |  superio_inb(SUPERIO_REG_BASE_LSB);
 
-       printk(KERN_INFO DRVNAME ": found SMSC %s "
-               "(base address 0x%04x, revision %u)\n",
+       pr_info("found SMSC %s (base address 0x%04x, revision %u)\n",
                name, *addr, rev);
 
        superio_exit();
index 8fa462f2b570e7c8692d62bbcc5ff5cb8675d781..f44a89aac381af7f93fb499e3a34d12eb9488ee6 100644 (file)
@@ -26,6 +26,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
@@ -435,30 +437,29 @@ static int __init smsc47m1_find(unsigned short *addr,
         */
        switch (val) {
        case 0x51:
-               pr_info(DRVNAME ": Found SMSC LPC47B27x\n");
+               pr_info("Found SMSC LPC47B27x\n");
                sio_data->type = smsc47m1;
                break;
        case 0x59:
-               pr_info(DRVNAME ": Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
+               pr_info("Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
                sio_data->type = smsc47m1;
                break;
        case 0x5F:
-               pr_info(DRVNAME ": Found SMSC LPC47M14x\n");
+               pr_info("Found SMSC LPC47M14x\n");
                sio_data->type = smsc47m1;
                break;
        case 0x60:
-               pr_info(DRVNAME ": Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
+               pr_info("Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
                sio_data->type = smsc47m1;
                break;
        case 0x6B:
                if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) {
-                       pr_debug(DRVNAME ": "
-                                "Found SMSC LPC47M233, unsupported\n");
+                       pr_debug("Found SMSC LPC47M233, unsupported\n");
                        superio_exit();
                        return -ENODEV;
                }
 
-               pr_info(DRVNAME ": Found SMSC LPC47M292\n");
+               pr_info("Found SMSC LPC47M292\n");
                sio_data->type = smsc47m2;
                break;
        default:
@@ -470,7 +471,7 @@ static int __init smsc47m1_find(unsigned short *addr,
        *addr = (superio_inb(SUPERIO_REG_BASE) << 8)
              |  superio_inb(SUPERIO_REG_BASE + 1);
        if (*addr == 0) {
-               pr_info(DRVNAME ": Device address not set, will not use\n");
+               pr_info("Device address not set, will not use\n");
                superio_exit();
                return -ENODEV;
        }
@@ -479,7 +480,7 @@ static int __init smsc47m1_find(unsigned short *addr,
         * Compaq Presario S4000NX) */
        sio_data->activate = superio_inb(SUPERIO_REG_ACT);
        if ((sio_data->activate & 0x01) == 0) {
-               pr_info(DRVNAME ": Enabling device\n");
+               pr_info("Enabling device\n");
                superio_outb(SUPERIO_REG_ACT, sio_data->activate | 0x01);
        }
 
@@ -494,7 +495,7 @@ static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
                superio_enter();
                superio_select();
 
-               pr_info(DRVNAME ": Disabling device\n");
+               pr_info("Disabling device\n");
                superio_outb(SUPERIO_REG_ACT, sio_data->activate);
 
                superio_exit();
@@ -823,28 +824,26 @@ static int __init smsc47m1_device_add(unsigned short address,
        pdev = platform_device_alloc(DRVNAME, address);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit;
        }
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device resource addition failed "
-                      "(%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
        err = platform_device_add_data(pdev, sio_data,
                                       sizeof(struct smsc47m1_sio_data));
        if (err) {
-               printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+               pr_err("Platform data allocation failed\n");
                goto exit_device_put;
        }
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
index ec7fad747adc51b6252c11e3b3a151208a8b9d32..0d18de424c66dca941cb2540c8f1d6aeb508fdd1 100644 (file)
@@ -21,6 +21,8 @@
  * 02110-1301 USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -202,7 +204,7 @@ static int __cpuinit via_cputemp_device_add(unsigned int cpu)
        pdev = platform_device_alloc(DRVNAME, cpu);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit;
        }
 
@@ -214,8 +216,7 @@ static int __cpuinit via_cputemp_device_add(unsigned int cpu)
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_free;
        }
 
@@ -237,13 +238,16 @@ exit:
 
 static void __cpuinit via_cputemp_device_remove(unsigned int cpu)
 {
-       struct pdev_entry *p, *n;
+       struct pdev_entry *p;
+
        mutex_lock(&pdev_list_mutex);
-       list_for_each_entry_safe(p, n, &pdev_list, list) {
+       list_for_each_entry(p, &pdev_list, list) {
                if (p->cpu == cpu) {
                        platform_device_unregister(p->pdev);
                        list_del(&p->list);
+                       mutex_unlock(&pdev_list_mutex);
                        kfree(p);
+                       return;
                }
        }
        mutex_unlock(&pdev_list_mutex);
@@ -273,7 +277,6 @@ static struct notifier_block via_cputemp_cpu_notifier __refdata = {
 static int __init via_cputemp_init(void)
 {
        int i, err;
-       struct pdev_entry *p, *n;
 
        if (cpu_data(0).x86_vendor != X86_VENDOR_CENTAUR) {
                printk(KERN_DEBUG DRVNAME ": Not a VIA CPU\n");
@@ -295,33 +298,27 @@ static int __init via_cputemp_init(void)
                        continue;
 
                if (c->x86_model > 0x0f) {
-                       printk(KERN_WARNING DRVNAME ": Unknown CPU "
-                               "model 0x%x\n", c->x86_model);
+                       pr_warn("Unknown CPU model 0x%x\n", c->x86_model);
                        continue;
                }
 
-               err = via_cputemp_device_add(i);
-               if (err)
-                       goto exit_devices_unreg;
+               via_cputemp_device_add(i);
        }
+
+#ifndef CONFIG_HOTPLUG_CPU
        if (list_empty(&pdev_list)) {
                err = -ENODEV;
                goto exit_driver_unreg;
        }
+#endif
 
        register_hotcpu_notifier(&via_cputemp_cpu_notifier);
        return 0;
 
-exit_devices_unreg:
-       mutex_lock(&pdev_list_mutex);
-       list_for_each_entry_safe(p, n, &pdev_list, list) {
-               platform_device_unregister(p->pdev);
-               list_del(&p->list);
-               kfree(p);
-       }
-       mutex_unlock(&pdev_list_mutex);
+#ifndef CONFIG_HOTPLUG_CPU
 exit_driver_unreg:
        platform_driver_unregister(&via_cputemp_driver);
+#endif
 exit:
        return err;
 }
index f397ce7ad5984d2347372d90053c6612cabfd345..13e8d218e49542ff87dd91a915b961239aa5195d 100644 (file)
@@ -30,6 +30,8 @@
     Warning - only supports a single device.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
@@ -791,21 +793,19 @@ static int __devinit via686a_device_add(unsigned short address)
        pdev = platform_device_alloc("via686a", address);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR "via686a: Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit;
        }
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR "via686a: Device resource addition failed "
-                      "(%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR "via686a: Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
index ae33bbb577c755b89759a319d3d88c81eff4048b..49163d48e9665c96faf0dadbddeb73000b49299c 100644 (file)
@@ -21,6 +21,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -1254,8 +1256,7 @@ static int __init vt1211_device_add(unsigned short address)
        pdev = platform_device_alloc(DRVNAME, address);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR DRVNAME ": Device allocation failed (%d)\n",
-                      err);
+               pr_err("Device allocation failed (%d)\n", err);
                goto EXIT;
        }
 
@@ -1266,15 +1267,13 @@ static int __init vt1211_device_add(unsigned short address)
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device resource addition failed "
-                      "(%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto EXIT_DEV_PUT;
        }
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto EXIT_DEV_PUT;
        }
 
@@ -1301,23 +1300,20 @@ static int __init vt1211_find(int sio_cip, unsigned short *address)
        superio_select(sio_cip, SIO_VT1211_LDN_HWMON);
 
        if ((superio_inb(sio_cip, SIO_VT1211_ACTIVE) & 1) == 0) {
-               printk(KERN_WARNING DRVNAME ": HW monitor is disabled, "
-                      "skipping\n");
+               pr_warn("HW monitor is disabled, skipping\n");
                goto EXIT;
        }
 
        *address = ((superio_inb(sio_cip, SIO_VT1211_BADDR) << 8) |
                    (superio_inb(sio_cip, SIO_VT1211_BADDR + 1))) & 0xff00;
        if (*address == 0) {
-               printk(KERN_WARNING DRVNAME ": Base address is not set, "
-                      "skipping\n");
+               pr_warn("Base address is not set, skipping\n");
                goto EXIT;
        }
 
        err = 0;
-       printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, "
-              "revision %u\n", *address,
-              superio_inb(sio_cip, SIO_VT1211_DEVREV));
+       pr_info("Found VT1211 chip at 0x%04x, revision %u\n",
+               *address, superio_inb(sio_cip, SIO_VT1211_DEVREV));
 
 EXIT:
        superio_exit(sio_cip);
@@ -1336,15 +1332,15 @@ static int __init vt1211_init(void)
 
        if ((uch_config < -1) || (uch_config > 31)) {
                err = -EINVAL;
-               printk(KERN_WARNING DRVNAME ": Invalid UCH configuration %d. "
-                      "Choose a value between 0 and 31.\n", uch_config);
+               pr_warn("Invalid UCH configuration %d. "
+                       "Choose a value between 0 and 31.\n", uch_config);
          goto EXIT;
        }
 
        if ((int_mode < -1) || (int_mode > 0)) {
                err = -EINVAL;
-               printk(KERN_WARNING DRVNAME ": Invalid interrupt mode %d. "
-                      "Only mode 0 is supported.\n", int_mode);
+               pr_warn("Invalid interrupt mode %d. "
+                       "Only mode 0 is supported.\n", int_mode);
          goto EXIT;
        }
 
index e6078c9f0e279d33e62df726c7feaace7e8fa36d..db3b2e8d2a671dcc5f40e9008128223d10cc5847 100644 (file)
@@ -24,6 +24,8 @@
 /* Supports VIA VT8231 South Bridge embedded sensors
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -902,21 +904,19 @@ static int __devinit vt8231_device_add(unsigned short address)
        pdev = platform_device_alloc("vt8231", address);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR "vt8231: Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit;
        }
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR "vt8231: Device resource addition failed "
-                      "(%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR "vt8231: Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
index 072c58008a633b713e1f68fd3a522572a41842d1..073eabedc432e37479891c71d0ba96c08fd94cad 100644 (file)
@@ -42,6 +42,8 @@
     w83667hg-b   9      5       3       3      0xb350 0xc1    0x5ca3
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -1668,8 +1670,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
                break;
        default:
                if (val != 0xffff)
-                       pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
-                                val);
+                       pr_debug("unsupported chip ID: 0x%04x\n", val);
                superio_exit(sioaddr);
                return -ENODEV;
        }
@@ -1680,8 +1681,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
            | superio_inb(sioaddr, SIO_REG_ADDR + 1);
        *addr = val & IOREGION_ALIGNMENT;
        if (*addr == 0) {
-               printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
-                      "device with a base I/O port 0.\n");
+               pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
                superio_exit(sioaddr);
                return -ENODEV;
        }
@@ -1689,13 +1689,12 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
        /* Activate logical device if needed */
        val = superio_inb(sioaddr, SIO_REG_ENABLE);
        if (!(val & 0x01)) {
-               printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
-                      "Sensor is probably unusable.\n");
+               pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
                superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
        }
 
        superio_exit(sioaddr);
-       pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
+       pr_info("Found %s chip at %#x\n", sio_name, *addr);
        sio_data->sioreg = sioaddr;
 
        return 0;
@@ -1729,14 +1728,14 @@ static int __init sensors_w83627ehf_init(void)
 
        if (!(pdev = platform_device_alloc(DRVNAME, address))) {
                err = -ENOMEM;
-               printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit_unregister;
        }
 
        err = platform_device_add_data(pdev, &sio_data,
                                       sizeof(struct w83627ehf_sio_data));
        if (err) {
-               printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+               pr_err("Platform data allocation failed\n");
                goto exit_device_put;
        }
 
@@ -1752,16 +1751,14 @@ static int __init sensors_w83627ehf_init(void)
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device resource addition failed "
-                      "(%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
        /* platform_device_add calls probe() */
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
index 38e2805230711f0b1b02e243b34dc62e4792c282..bde50e34d01322144639695d0608ec14144ed84f 100644 (file)
@@ -39,6 +39,8 @@
     supported yet.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -1166,14 +1168,13 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
               superio_inb(sio_data, WINB_BASE_REG + 1);
        *addr = val & WINB_ALIGNMENT;
        if (*addr == 0) {
-               printk(KERN_WARNING DRVNAME ": Base address not set, "
-                      "skipping\n");
+               pr_warn("Base address not set, skipping\n");
                goto exit;
        }
 
        val = superio_inb(sio_data, WINB_ACT_REG);
        if (!(val & 0x01)) {
-               printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
+               pr_warn("Enabling HWM logical device\n");
                superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
        }
 
@@ -1789,28 +1790,26 @@ static int __init w83627hf_device_add(unsigned short address,
        pdev = platform_device_alloc(DRVNAME, address);
        if (!pdev) {
                err = -ENOMEM;
-               printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+               pr_err("Device allocation failed\n");
                goto exit;
        }
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device resource addition failed "
-                      "(%d)\n", err);
+               pr_err("Device resource addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
        err = platform_device_add_data(pdev, sio_data,
                                       sizeof(struct w83627hf_sio_data));
        if (err) {
-               printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+               pr_err("Platform data allocation failed\n");
                goto exit_device_put;
        }
 
        err = platform_device_add(pdev);
        if (err) {
-               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-                      err);
+               pr_err("Device addition failed (%d)\n", err);
                goto exit_device_put;
        }
 
index dbf741c95835f953c8d6d554f7f087286f3c9381..23cf8fc933ec037c40251d0c855e736e00141dc8 100644 (file)
@@ -121,7 +121,7 @@ static int gameport_measure_speed(struct gameport *gameport)
        }
 
        gameport_close(gameport);
-       return (cpu_data(raw_smp_processor_id()).loops_per_jiffy *
+       return (this_cpu_read(cpu_info.loops_per_jiffy) *
                (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
 
 #else
index b952317639116f2f18a7bc1f41ff5887c17f2a49..ee82851afe3ee9a660873b59d5fcb8cf39181ca7 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI   0x0236
 #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO    0x0237
 #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS    0x0238
+/* MacbookAir3,2 (unibody), aka wellspring5 */
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI   0x023f
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO    0x0240
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS    0x0241
+/* MacbookAir3,1 (unibody), aka wellspring4 */
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI  0x0242
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO   0x0243
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS   0x0244
 
 #define BCM5974_DEVICE(prod) {                                 \
        .match_flags = (USB_DEVICE_ID_MATCH_DEVICE |            \
@@ -80,6 +88,14 @@ static const struct usb_device_id bcm5974_table[] = {
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
+       /* MacbookAir3,2 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ISO),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_JIS),
+       /* MacbookAir3,1 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
        /* Terminating entry */
        {}
 };
@@ -234,6 +250,30 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                { DIM_X, DIM_X / SN_COORD, -4460, 5166 },
                { DIM_Y, DIM_Y / SN_COORD, -75, 6700 }
        },
+       {
+               USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI,
+               USB_DEVICE_ID_APPLE_WELLSPRING4_ISO,
+               USB_DEVICE_ID_APPLE_WELLSPRING4_JIS,
+               HAS_INTEGRATED_BUTTON,
+               0x84, sizeof(struct bt_data),
+               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+               { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
+               { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+       },
+       {
+               USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI,
+               USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO,
+               USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS,
+               HAS_INTEGRATED_BUTTON,
+               0x84, sizeof(struct bt_data),
+               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+               { DIM_X, DIM_X / SN_COORD, -4616, 5112 },
+               { DIM_Y, DIM_Y / SN_COORD, -142, 5234 }
+       },
        {}
 };
 
index e54e79d4e2c124310e552f3daccb512d5cff25c2..92607ed25e2ec5569c85881f95db37237bf36bfc 100644 (file)
@@ -2297,6 +2297,7 @@ static int __init capidrv_init(void)
 
        errcode = capi20_get_profile(0, &profile);
        if (errcode != CAPI_NOERROR) {
+               unregister_capictr_notifier(&capictr_nb);
                capi20_release(&global.ap);
                return -EIO;
        }
index 3acf94cc5acda3f056db58b559a8af477f6ae76a..2b33b2627fce5052fdf252ac13d225590c379f37 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/rcupdate.h>
 
 static int showcapimsgs = 0;
+static struct workqueue_struct *kcapi_wq;
 
 MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");
 MODULE_AUTHOR("Carsten Paeth");
@@ -291,7 +292,7 @@ static int notify_push(unsigned int event_type, u32 controller)
        event->type = event_type;
        event->controller = controller;
 
-       schedule_work(&event->work);
+       queue_work(kcapi_wq, &event->work);
        return 0;
 }
 
@@ -408,7 +409,7 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
                goto error;
        }
        skb_queue_tail(&ap->recv_queue, skb);
-       schedule_work(&ap->recv_work);
+       queue_work(kcapi_wq, &ap->recv_work);
        rcu_read_unlock();
 
        return;
@@ -743,7 +744,7 @@ u16 capi20_release(struct capi20_appl *ap)
 
        mutex_unlock(&capi_controller_lock);
 
-       flush_scheduled_work();
+       flush_workqueue(kcapi_wq);
        skb_queue_purge(&ap->recv_queue);
 
        if (showcapimsgs & 1) {
@@ -1285,21 +1286,30 @@ static int __init kcapi_init(void)
 {
        int err;
 
+       kcapi_wq = alloc_workqueue("kcapi", 0, 0);
+       if (!kcapi_wq)
+               return -ENOMEM;
+
        register_capictr_notifier(&capictr_nb);
 
        err = cdebug_init();
-       if (!err)
-               kcapi_proc_init();
-       return err;
+       if (err) {
+               unregister_capictr_notifier(&capictr_nb);
+               destroy_workqueue(kcapi_wq);
+               return err;
+       }
+
+       kcapi_proc_init();
+       return 0;
 }
 
 static void __exit kcapi_exit(void)
 {
         kcapi_proc_exit();
 
-       /* make sure all notifiers are finished */
-       flush_scheduled_work();
+       unregister_capictr_notifier(&capictr_nb);
        cdebug_exit();
+       destroy_workqueue(kcapi_wq);
 }
 
 module_init(kcapi_init);
index 307bd6e8988bed710830db7ddbb3ce8c3a08aac4..199f374cf9da42173c15a3b10b9d7387bf84fab0 100644 (file)
@@ -110,7 +110,7 @@ mISDN_freedchannel(struct dchannel *ch)
        }
        skb_queue_purge(&ch->squeue);
        skb_queue_purge(&ch->rqueue);
-       flush_scheduled_work();
+       flush_work_sync(&ch->workq);
        return 0;
 }
 EXPORT_SYMBOL(mISDN_freedchannel);
@@ -143,7 +143,7 @@ mISDN_freebchannel(struct bchannel *ch)
        mISDN_clear_bchannel(ch);
        skb_queue_purge(&ch->rqueue);
        ch->rcount = 0;
-       flush_scheduled_work();
+       flush_work_sync(&ch->workq);
        return 0;
 }
 EXPORT_SYMBOL(mISDN_freebchannel);
index 5b59796ed250f53ae4e3a261583cd60a525a0cc1..bd526f664a3966217f0317497a943deba197982e 100644 (file)
@@ -1269,6 +1269,8 @@ release_card(struct l1oip *hc)
        if (timer_pending(&hc->timeout_tl))
                del_timer(&hc->timeout_tl);
 
+       cancel_work_sync(&hc->workq);
+
        if (hc->socket_thread)
                l1oip_socket_close(hc);
 
index 5aab32ce4f4d2a18e1f7997482a79925e75aa39d..a04523273282c76b247740b65d9a43fc452352ac 100644 (file)
@@ -276,7 +276,7 @@ static int wm8350_led_remove(struct platform_device *pdev)
        struct wm8350_led *led = platform_get_drvdata(pdev);
 
        led_classdev_unregister(&led->cdev);
-       flush_scheduled_work();
+       flush_work_sync(&led->work);
        wm8350_led_disable(led);
        regulator_put(led->dcdc);
        regulator_put(led->isink);
index 2ad62c339cd2c9cf849dc3a551a8d47548ef2190..399beb1638d1aa9acf009c1c05aeb9cf1bc79af2 100644 (file)
@@ -226,7 +226,7 @@ void ams_sensor_detach(void)
         * We do this after ams_info.exit(), because an interrupt might
         * have arrived before disabling them.
         */
-       flush_scheduled_work();
+       flush_work_sync(&ams_info.worker);
 
        /* Remove device */
        of_device_unregister(ams_info.of_dev);
index 53cce3a5da2336b97fd94e0bd55123be2968adbf..39f660b2a60d4516c2e855852b947db72fc6a532 100644 (file)
@@ -285,8 +285,8 @@ static void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm)
 
 static void __devexit rackmeter_stop_cpu_sniffer(struct rackmeter *rm)
 {
-       cancel_rearming_delayed_work(&rm->cpu[0].sniffer);
-       cancel_rearming_delayed_work(&rm->cpu[1].sniffer);
+       cancel_delayed_work_sync(&rm->cpu[0].sniffer);
+       cancel_delayed_work_sync(&rm->cpu[1].sniffer);
 }
 
 static int __devinit rackmeter_setup(struct rackmeter *rm)
index 4df42aaae7f708801663dfc3eea018ee7ed9cfc8..51752a9ef7a4e82c3f1519bf6d488376d5eeb98e 100644 (file)
@@ -1329,7 +1329,8 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
                return -EBUSY;
 
        dvb_net_stop(net);
-       flush_scheduled_work();
+       flush_work_sync(&priv->set_multicast_list_wq);
+       flush_work_sync(&priv->restart_net_feed_wq);
        printk("dvb_net: removed network interface %s\n", net->name);
        unregister_netdev(net);
        dvbnet->state[num]=0;
index c6498f536dffda3b7015400b8af8c88e8a37fb0f..23005b3cf30bedaea413a1afba3627fe28d0d400 100644 (file)
@@ -313,8 +313,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
 int dvb_usb_remote_exit(struct dvb_usb_device *d)
 {
        if (d->state & DVB_USB_STATE_REMOTE) {
-               cancel_rearming_delayed_work(&d->rc_query_work);
-               flush_scheduled_work();
+               cancel_delayed_work_sync(&d->rc_query_work);
                if (d->props.rc.mode == DVB_RC_LEGACY)
                        input_unregister_device(d->input_dev);
                else
index a7b369a439d67f5b6ca5a1c30f6a3d8c74e6f656..9f73c2cfc9eae18af23eeafdeb08b97c66409571 100644 (file)
@@ -111,7 +111,7 @@ void mantis_evmgr_exit(struct mantis_ca *ca)
        struct mantis_pci *mantis = ca->ca_priv;
 
        dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting");
-       flush_scheduled_work();
+       flush_work_sync(&ca->hif_evm_work);
        mantis_hif_exit(ca);
        mantis_pcmcia_exit(ca);
 }
index 7d2f2398fa8b609cdd402d4503ac9cb2cabac0d8..97b889e8a341969017480dea347700a8e5255767 100644 (file)
@@ -182,5 +182,6 @@ void mantis_uart_exit(struct mantis_pci *mantis)
 {
        /* disable interrupt */
        mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+       flush_work_sync(&mantis->uart_work);
 }
 EXPORT_SYMBOL_GPL(mantis_uart_exit);
index 849cd170b821d7fd4646a33b8cd05c517cf9e28a..91399c94cd18901bd657958ec3f4197f2649f043 100644 (file)
@@ -189,8 +189,14 @@ static void request_modules(struct bttv *dev)
        INIT_WORK(&dev->request_module_wk, request_module_async);
        schedule_work(&dev->request_module_wk);
 }
+
+static void flush_request_modules(struct bttv *dev)
+{
+       flush_work_sync(&dev->request_module_wk);
+}
 #else
 #define request_modules(dev)
+#define flush_request_modules(dev)
 #endif /* CONFIG_MODULES */
 
 
@@ -4429,6 +4435,9 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
        if (bttv_verbose)
                printk("bttv%d: unloading\n",btv->c.nr);
 
+       if (bttv_tvcards[btv->c.type].has_dvb)
+               flush_request_modules(btv);
+
        /* shutdown everything (DMA+IRQs) */
        btand(~15, BT848_GPIO_DMA_CTL);
        btwrite(0, BT848_INT_MASK);
index 97793b9606007dcd6e67eb9a9c482e724d8c3a82..e8b64bca9db22b1c5d72a89b740653060fb864fd 100644 (file)
@@ -319,16 +319,13 @@ static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
 
 static void bttv_ir_stop(struct bttv *btv)
 {
-       if (btv->remote->polling) {
+       if (btv->remote->polling)
                del_timer_sync(&btv->remote->timer);
-               flush_scheduled_work();
-       }
 
        if (btv->remote->rc5_gpio) {
                u32 gpio;
 
                del_timer_sync(&btv->remote->timer);
-               flush_scheduled_work();
 
                gpio = bttv_gpio_read(&btv->c);
                bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
index 676e5bef89ebaaaf677fa19d349ae98ff927c191..133ec2bac18053018b547a45afd99fccd3a010b8 100644 (file)
@@ -267,8 +267,14 @@ static void request_modules(struct cx18 *dev)
        INIT_WORK(&dev->request_module_wk, request_module_async);
        schedule_work(&dev->request_module_wk);
 }
+
+static void flush_request_modules(struct cx18 *dev)
+{
+       flush_work_sync(&dev->request_module_wk);
+}
 #else
 #define request_modules(dev)
+#define flush_request_modules(dev)
 #endif /* CONFIG_MODULES */
 
 /* Generic utility functions */
@@ -1233,6 +1239,8 @@ static void cx18_remove(struct pci_dev *pci_dev)
 
        CX18_DEBUG_INFO("Removing Card\n");
 
+       flush_request_modules(cx);
+
        /* Stop all captures */
        CX18_DEBUG_INFO("Stopping all streams\n");
        if (atomic_read(&cx->tot_capturing) > 0)
index 6905607ffca36f6f54c3340a4c3975b018120d6e..588f3e8f028b28c04db0c381abfaf62421a9b2ec 100644 (file)
@@ -813,8 +813,14 @@ static void request_modules(struct cx231xx *dev)
        INIT_WORK(&dev->request_module_wk, request_module_async);
        schedule_work(&dev->request_module_wk);
 }
+
+static void flush_request_modules(struct cx231xx *dev)
+{
+       flush_work_sync(&dev->request_module_wk);
+}
 #else
 #define request_modules(dev)
+#define flush_request_modules(dev)
 #endif /* CONFIG_MODULES */
 
 /*
@@ -1147,6 +1153,8 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
        if (!dev->udev)
                return;
 
+       flush_request_modules(dev);
+
        /* delete v4l2 device */
        v4l2_device_unregister(&dev->v4l2_dev);
 
index 0b0d0664382ae07c6c3a2504decaab3808ea215a..199b9964bbe5ab27776b9dd2f9d2d59dd96c9a2b 100644 (file)
@@ -229,8 +229,6 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev)
                v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
                v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
        }
-
-       flush_scheduled_work();
 }
 
 static void cx23885_input_ir_close(struct rc_dev *rc)
index f7d71acbb0780969041d19800fe33d3da6e82d24..addf9545e9bf42d6dac1591377e843763cee9305 100644 (file)
@@ -66,8 +66,14 @@ static void request_modules(struct cx8802_dev *dev)
        INIT_WORK(&dev->request_module_wk, request_module_async);
        schedule_work(&dev->request_module_wk);
 }
+
+static void flush_request_modules(struct cx8802_dev *dev)
+{
+       flush_work_sync(&dev->request_module_wk);
+}
 #else
 #define request_modules(dev)
+#define flush_request_modules(dev)
 #endif /* CONFIG_MODULES */
 
 
@@ -819,6 +825,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
 
        dprintk( 1, "%s\n", __func__);
 
+       flush_request_modules(dev);
+
        if (!list_empty(&dev->drvlist)) {
                struct cx8802_driver *drv, *tmp;
                int err;
index 8af302b425b3eba754279807ff1413033dff18ad..099d5df8c572dfc77e2ee1a85403a3b1a7b52bde 100644 (file)
@@ -2690,8 +2690,14 @@ static void request_modules(struct em28xx *dev)
        INIT_WORK(&dev->request_module_wk, request_module_async);
        schedule_work(&dev->request_module_wk);
 }
+
+static void flush_request_modules(struct em28xx *dev)
+{
+       flush_work_sync(&dev->request_module_wk);
+}
 #else
 #define request_modules(dev)
+#define flush_request_modules(dev)
 #endif /* CONFIG_MODULES */
 
 /*
@@ -3118,6 +3124,8 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 
        em28xx_info("disconnecting %s\n", dev->vdev->name);
 
+       flush_request_modules(dev);
+
        /* wait until all current v4l2 io is finished then deallocate
           resources */
        mutex_lock(&dev->lock);
index 29cc74441a7d3d63686dbfa5cd8c046f00023f9c..ba1ba8648c8169c074fdcb497643d6ad05a5197b 100644 (file)
@@ -551,7 +551,7 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev)
 {
        if (dev->sbutton_input_dev != NULL) {
                em28xx_info("Deregistering snapshot button\n");
-               cancel_rearming_delayed_work(&dev->sbutton_query_work);
+               cancel_delayed_work_sync(&dev->sbutton_query_work);
                input_unregister_device(dev->sbutton_input_dev);
                dev->sbutton_input_dev = NULL;
        }
index 378b094aff16867a35f320da2bfe230b17fbc07a..01755276290251dfdb1ca70a26a1c61c4636c14c 100644 (file)
@@ -1198,7 +1198,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
 
        atomic_inc(&cam->reset_disable);
 
-       flush_scheduled_work();
+       flush_work_sync(&cam->sensor_reset_work);
 
        rval = videobuf_streamoff(q);
        if (!rval) {
@@ -1512,7 +1512,7 @@ static int omap24xxcam_release(struct file *file)
 
        atomic_inc(&cam->reset_disable);
 
-       flush_scheduled_work();
+       flush_work_sync(&cam->sensor_reset_work);
 
        /* stop streaming capture */
        videobuf_streamoff(&fh->vbq);
@@ -1536,7 +1536,7 @@ static int omap24xxcam_release(struct file *file)
         * not be scheduled anymore since streaming is already
         * disabled.)
         */
-       flush_scheduled_work();
+       flush_work_sync(&cam->sensor_reset_work);
 
        mutex_lock(&cam->mutex);
        if (atomic_dec_return(&cam->users) == 0) {
index 756a27812260ac2882dfbfa384ca9b2e3a32be4d..6abeecff6da7b5d7bbaa5856a464b981eb90c8f0 100644 (file)
@@ -166,8 +166,14 @@ static void request_submodules(struct saa7134_dev *dev)
        schedule_work(&dev->request_module_wk);
 }
 
+static void flush_request_submodules(struct saa7134_dev *dev)
+{
+       flush_work_sync(&dev->request_module_wk);
+}
+
 #else
 #define request_submodules(dev)
+#define flush_request_submodules(dev)
 #endif /* CONFIG_MODULES */
 
 /* ------------------------------------------------------------------ */
@@ -1010,8 +1016,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
                }
        }
 
-       request_submodules(dev);
-
        v4l2_prio_init(&dev->prio);
 
        mutex_lock(&saa7134_devlist_lock);
@@ -1066,6 +1070,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        if (saa7134_dmasound_init && !dev->dmasound.priv_data)
                saa7134_dmasound_init(dev);
 
+       request_submodules(dev);
        return 0;
 
  fail4:
@@ -1091,6 +1096,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
        struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
        struct saa7134_mpeg_ops *mops;
 
+       flush_request_submodules(dev);
+
        /* Release DMA sound modules if present */
        if (saa7134_dmasound_exit && dev->dmasound.priv_data) {
                saa7134_dmasound_exit(dev);
index b890aafe7d640bcc141b2c6edddb3009d73c5245..6b8459c7728e472c1d927a2a066e7cc77fcebd2a 100644 (file)
@@ -553,7 +553,7 @@ static int empress_fini(struct saa7134_dev *dev)
 
        if (NULL == dev->empress_dev)
                return 0;
-       flush_scheduled_work();
+       flush_work_sync(&dev->empress_workqueue);
        video_unregister_device(dev->empress_dev);
        dev->empress_dev = NULL;
        return 0;
index 4ba85bbdb4c12b60bdb6944223d4a467626f7c3e..9cee8e7f0bcb1297116667de77ab1d3f49ce1213 100644 (file)
@@ -1259,7 +1259,7 @@ static int menelaus_probe(struct i2c_client *client,
        return 0;
 fail2:
        free_irq(client->irq, menelaus);
-       flush_scheduled_work();
+       flush_work_sync(&menelaus->work);
 fail1:
        kfree(menelaus);
        return err;
@@ -1270,6 +1270,7 @@ static int __exit menelaus_remove(struct i2c_client *client)
        struct menelaus_chip    *menelaus = i2c_get_clientdata(client);
 
        free_irq(client->irq, menelaus);
+       flush_work_sync(&menelaus->work);
        kfree(menelaus);
        the_menelaus = NULL;
        return 0;
index d0016b67d125ce40b8d9a810f1abb7ade2678756..90187fe33e0449d15b569482bd843f104735030a 100644 (file)
@@ -242,7 +242,7 @@ static int dbg_show(struct seq_file *s, void *_)
        seq_printf(s, "mask2     %s\n", buf);
        /* ignore ackint2 */
 
-       (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
+       schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
 
 
        /* VMAIN voltage, enable lowpower, etc */
@@ -400,7 +400,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
                        && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)))
                poll = 1;
        if (poll)
-               (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
+               schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
 
        /* also potentially gpio-in rise or fall */
 }
@@ -410,7 +410,7 @@ static void tps65010_work(struct work_struct *work)
 {
        struct tps65010         *tps;
 
-       tps = container_of(work, struct tps65010, work.work);
+       tps = container_of(to_delayed_work(work), struct tps65010, work);
        mutex_lock(&tps->lock);
 
        tps65010_interrupt(tps);
@@ -448,7 +448,7 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
 
        disable_irq_nosync(irq);
        set_bit(FLAG_IRQ_ENABLE, &tps->flags);
-       (void) schedule_work(&tps->work.work);
+       schedule_delayed_work(&tps->work, 0);
        return IRQ_HANDLED;
 }
 
@@ -527,8 +527,7 @@ static int __exit tps65010_remove(struct i2c_client *client)
        }
        if (client->irq > 0)
                free_irq(client->irq, tps);
-       cancel_delayed_work(&tps->work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&tps->work);
        debugfs_remove(tps->file);
        kfree(tps);
        the_tps = NULL;
@@ -720,7 +719,7 @@ int tps65010_set_vbus_draw(unsigned mA)
                        && test_and_set_bit(
                                FLAG_VBUS_CHANGED, &the_tps->flags)) {
                /* gadget drivers call this in_irq() */
-               (void) schedule_work(&the_tps->work.work);
+               schedule_delayed_work(&the_tps->work, 0);
        }
        local_irq_restore(flags);
 
index 559b0b3c16c379584be01a08db209e2437549a04..ab1ad41786d118327a5cb7210486454430de8f8c 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/log2.h>
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
+#include <linux/of.h>
 #include <linux/i2c.h>
 #include <linux/i2c/at24.h>
 
@@ -457,6 +458,27 @@ static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf,
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef CONFIG_OF
+static void at24_get_ofdata(struct i2c_client *client,
+               struct at24_platform_data *chip)
+{
+       const __be32 *val;
+       struct device_node *node = client->dev.of_node;
+
+       if (node) {
+               if (of_get_property(node, "read-only", NULL))
+                       chip->flags |= AT24_FLAG_READONLY;
+               val = of_get_property(node, "pagesize", NULL);
+               if (val)
+                       chip->page_size = be32_to_cpup(val);
+       }
+}
+#else
+static void at24_get_ofdata(struct i2c_client *client,
+               struct at24_platform_data *chip)
+{ }
+#endif /* CONFIG_OF */
+
 static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        struct at24_platform_data chip;
@@ -485,6 +507,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
                 */
                chip.page_size = 1;
 
+               /* update chipdata if OF is present */
+               at24_get_ofdata(client, &chip);
+
                chip.setup = NULL;
                chip.context = NULL;
        }
@@ -492,6 +517,11 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
        if (!is_power_of_2(chip.byte_len))
                dev_warn(&client->dev,
                        "byte_len looks suspicious (no power of 2)!\n");
+       if (!chip.page_size) {
+               dev_err(&client->dev, "page_size must not be 0!\n");
+               err = -EINVAL;
+               goto err_out;
+       }
        if (!is_power_of_2(chip.page_size))
                dev_warn(&client->dev,
                        "page_size looks suspicious (no power of 2)!\n");
@@ -597,19 +627,15 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
        i2c_set_clientdata(client, at24);
 
-       dev_info(&client->dev, "%zu byte %s EEPROM %s\n",
+       dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",
                at24->bin.size, client->name,
-               writable ? "(writable)" : "(read-only)");
+               writable ? "writable" : "read-only", at24->write_max);
        if (use_smbus == I2C_SMBUS_WORD_DATA ||
            use_smbus == I2C_SMBUS_BYTE_DATA) {
                dev_notice(&client->dev, "Falling back to %s reads, "
                           "performance will suffer\n", use_smbus ==
                           I2C_SMBUS_WORD_DATA ? "word" : "byte");
        }
-       dev_dbg(&client->dev,
-               "page_size %d, num_addresses %d, write_max %d, use_smbus %d\n",
-               chip.page_size, num_addresses,
-               at24->write_max, use_smbus);
 
        /* export data to kernel code */
        if (chip.setup)
@@ -660,6 +686,11 @@ static struct i2c_driver at24_driver = {
 
 static int __init at24_init(void)
 {
+       if (!io_limit) {
+               pr_err("at24: io_limit must not be 0!\n");
+               return -EINVAL;
+       }
+
        io_limit = rounddown_pow_of_two(io_limit);
        return i2c_add_driver(&at24_driver);
 }
index 193206602d88946112f02e189bee1ee9b2b2ab65..668d41e594a9bed240ac4863364f0b26e9f4bb9b 100644 (file)
@@ -273,13 +273,11 @@ ioc4_variant(struct ioc4_driver_data *idd)
 static void __devinit
 ioc4_load_modules(struct work_struct *work)
 {
-       /* arg just has to be freed */
-
        request_module("sgiioc4");
-
-       kfree(work);
 }
 
+static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules);
+
 /* Adds a new instance of an IOC4 card */
 static int __devinit
 ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
@@ -396,21 +394,12 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
         * PCI device.
         */
        if (idd->idd_variant != IOC4_VARIANT_PCI_RT) {
-               struct work_struct *work;
-               work = kzalloc(sizeof(struct work_struct), GFP_KERNEL);
-               if (!work) {
-                       printk(KERN_WARNING
-                              "%s: IOC4 unable to allocate memory for "
-                              "load of sub-modules.\n", __func__);
-               } else {
-                       /* Request the module from a work procedure as the
-                        * modprobe goes out to a userland helper and that
-                        * will hang if done directly from ioc4_probe().
-                        */
-                       printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n");
-                       INIT_WORK(work, ioc4_load_modules);
-                       schedule_work(work);
-               }
+               /* Request the module from a work procedure as the modprobe
+                * goes out to a userland helper and that will hang if done
+                * directly from ioc4_probe().
+                */
+               printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n");
+               schedule_work(&ioc4_load_modules_work);
        }
 
        return 0;
@@ -498,7 +487,7 @@ static void __exit
 ioc4_exit(void)
 {
        /* Ensure ioc4_load_modules() has completed before exiting */
-       flush_scheduled_work();
+       flush_work_sync(&ioc4_load_modules_work);
        pci_unregister_driver(&ioc4_driver);
 }
 
index 57dcf8fa774a7302be1fbb6f0104d6320c6287c8..a3a780faf85adf373d6d8c37242f6f2a406acd6c 100644 (file)
@@ -1790,7 +1790,7 @@ static int __init mmc_init(void)
 {
        int ret;
 
-       workqueue = create_singlethread_workqueue("kmmcd");
+       workqueue = alloc_ordered_workqueue("kmmcd", 0);
        if (!workqueue)
                return -ENOMEM;
 
index d618e867399686e4d11916a72e434325ab135e6c..e960a9300eb21629928065b34df1f2c708b40f0f 100644 (file)
@@ -83,7 +83,7 @@ config MMC_RICOH_MMC
 
 config MMC_SDHCI_OF
        tristate "SDHCI support on OpenFirmware platforms"
-       depends on MMC_SDHCI && PPC_OF
+       depends on MMC_SDHCI && OF
        help
          This selects the OF support for Secure Digital Host Controller
          Interfaces.
@@ -93,6 +93,7 @@ config MMC_SDHCI_OF
 config MMC_SDHCI_OF_ESDHC
        bool "SDHCI OF support for the Freescale eSDHC controller"
        depends on MMC_SDHCI_OF
+       depends on PPC_OF
        select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
        help
          This selects the Freescale eSDHC controller support.
@@ -102,6 +103,7 @@ config MMC_SDHCI_OF_ESDHC
 config MMC_SDHCI_OF_HLWD
        bool "SDHCI OF support for the Nintendo Wii SDHCI controllers"
        depends on MMC_SDHCI_OF
+       depends on PPC_OF
        select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
        help
          This selects the Secure Digital Host Controller Interface (SDHCI)
index 0c7e37f496efae9f8e24179f6f907a5f3b696abe..379d2ffe4c871f66805a92a4f04f113d39dac6b6 100644 (file)
@@ -173,6 +173,8 @@ struct mmc_omap_host {
        struct omap_mmc_platform_data *pdata;
 };
 
+static struct workqueue_struct *mmc_omap_wq;
+
 static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
 {
        unsigned long tick_ns;
@@ -289,7 +291,7 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)
                host->next_slot = new_slot;
                host->mmc = new_slot->mmc;
                spin_unlock_irqrestore(&host->slot_lock, flags);
-               schedule_work(&host->slot_release_work);
+               queue_work(mmc_omap_wq, &host->slot_release_work);
                return;
        }
 
@@ -457,7 +459,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
        }
 
        host->stop_data = data;
-       schedule_work(&host->send_stop_work);
+       queue_work(mmc_omap_wq, &host->send_stop_work);
 }
 
 static void
@@ -637,7 +639,7 @@ mmc_omap_cmd_timer(unsigned long data)
                OMAP_MMC_WRITE(host, IE, 0);
                disable_irq(host->irq);
                host->abort = 1;
-               schedule_work(&host->cmd_abort_work);
+               queue_work(mmc_omap_wq, &host->cmd_abort_work);
        }
        spin_unlock_irqrestore(&host->slot_lock, flags);
 }
@@ -826,7 +828,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
                host->abort = 1;
                OMAP_MMC_WRITE(host, IE, 0);
                disable_irq_nosync(host->irq);
-               schedule_work(&host->cmd_abort_work);
+               queue_work(mmc_omap_wq, &host->cmd_abort_work);
                return IRQ_HANDLED;
        }
 
@@ -1387,7 +1389,7 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot)
 
        tasklet_kill(&slot->cover_tasklet);
        del_timer_sync(&slot->cover_timer);
-       flush_scheduled_work();
+       flush_workqueue(mmc_omap_wq);
 
        mmc_remove_host(mmc);
        mmc_free_host(mmc);
@@ -1608,12 +1610,22 @@ static struct platform_driver mmc_omap_driver = {
 
 static int __init mmc_omap_init(void)
 {
-       return platform_driver_probe(&mmc_omap_driver, mmc_omap_probe);
+       int ret;
+
+       mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0);
+       if (!mmc_omap_wq)
+               return -ENOMEM;
+
+       ret = platform_driver_probe(&mmc_omap_driver, mmc_omap_probe);
+       if (ret)
+               destroy_workqueue(mmc_omap_wq);
+       return ret;
 }
 
 static void __exit mmc_omap_exit(void)
 {
        platform_driver_unregister(&mmc_omap_driver);
+       destroy_workqueue(mmc_omap_wq);
 }
 
 module_init(mmc_omap_init);
index 5d46021cbb57f3a75b995ba11c25fa518aae9f37..078fdf11af030a966e117e7b0a0e80bffaf80206 100644 (file)
@@ -2290,7 +2290,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
                free_irq(host->irq, host);
                if (mmc_slot(host).card_detect_irq)
                        free_irq(mmc_slot(host).card_detect_irq, host);
-               flush_scheduled_work();
+               flush_work_sync(&host->mmc_carddetect_work);
 
                mmc_host_disable(host->mmc);
                clk_disable(host->iclk);
index c51b71174c1de1df6dce05482d8b2eb13b4d519e..fa19d849a9202ad0a9390ee96fae6a3e9647594e 100644 (file)
@@ -122,7 +122,7 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev,
        struct sdhci_of_data *sdhci_of_data = match->data;
        struct sdhci_host *host;
        struct sdhci_of_host *of_host;
-       const u32 *clk;
+       const __be32 *clk;
        int size;
        int ret;
 
@@ -166,7 +166,7 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev,
 
        clk = of_get_property(np, "clock-frequency", &size);
        if (clk && size == sizeof(*clk) && *clk)
-               of_host->clock = *clk;
+               of_host->clock = be32_to_cpup(clk);
 
        ret = sdhci_add_host(host);
        if (ret)
index 1e2cbf5d9aa11200697a23d0b20f8f35435839b6..b1f76891739554231cb6106c0ca94ce008bcd45b 100644 (file)
@@ -159,7 +159,7 @@ config MTD_AFS_PARTS
 
 config MTD_OF_PARTS
        tristate "Flash partition map based on OF description"
-       depends on (MICROBLAZE || PPC_OF) && MTD_PARTITIONS
+       depends on OF && MTD_PARTITIONS
        help
          This provides a partition parsing function which derives
          the partition map from the children of the flash node,
index a0dd7bba9481ce1e3480ffe0ee55902994653731..5d37d315fa98e18d37d58fa77410e7fa80954b26 100644 (file)
@@ -72,7 +72,7 @@ config MTD_PHYSMAP_BANKWIDTH
 
 config MTD_PHYSMAP_OF
        tristate "Flash device in physical memory map based on OF description"
-       depends on (MICROBLAZE || PPC_OF) && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
+       depends on OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
        help
          This provides a 'mapping' driver which allows the NOR Flash and
          ROM driver code to communicate with chips which are mapped
index 4da384cc7603aefb65b38bd2c3a2200a4e8d9470..31fe980e4e28e5c102780aa6d9ae8450cc224763 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
 #include <linux/if_bonding.h>
-#include <linux/kobject.h>
 #include <linux/cpumask.h>
 #include <linux/in6.h>
 #include "bond_3ad.h"
index 4c6028512d102ef937662b60382929dacb84df4d..a683fd3bb624d532c99fac0ac51166a366e525a8 100644 (file)
@@ -22,7 +22,7 @@ static int my3126_interrupt_enable(struct cphy *cphy)
 
 static int my3126_interrupt_disable(struct cphy *cphy)
 {
-       cancel_rearming_delayed_work(&cphy->phy_update);
+       cancel_delayed_work_sync(&cphy->phy_update);
        return 0;
 }
 
index d684f187de57714f4b38a2e7e8bf58771234d0a5..7a1f3d0ffa789918b75419741824b24fd84e4e10 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 #include <linux/of_gpio.h>
+#include <linux/of_net.h>
 
 #include <linux/vmalloc.h>
 #include <asm/pgtable.h>
index 45c4b7bfcf398929b36382217cb62519bd891a3c..6de4675016b5303e186d3c2350c8a81b0c98ae7c 100644 (file)
@@ -95,6 +95,7 @@
 #include <linux/phy.h>
 #include <linux/phy_fixed.h>
 #include <linux/of.h>
+#include <linux/of_net.h>
 
 #include "gianfar.h"
 #include "fsl_pq_mdio.h"
index 8f11d29a5828227d29d596d0c484f312a81a4978..6d9275c52e057d7348af153620bccf7ed8984a9e 100644 (file)
@@ -1279,7 +1279,7 @@ static void emac_force_link_update(struct emac_instance *dev)
        netif_carrier_off(dev->ndev);
        smp_rmb();
        if (dev->link_polling) {
-               cancel_rearming_delayed_work(&dev->link_work);
+               cancel_delayed_work_sync(&dev->link_work);
                if (dev->link_polling)
                        schedule_delayed_work(&dev->link_work,  PHY_POLL_LINK_OFF);
        }
@@ -1294,7 +1294,7 @@ static int emac_close(struct net_device *ndev)
 
        if (dev->phy.address >= 0) {
                dev->link_polling = 0;
-               cancel_rearming_delayed_work(&dev->link_work);
+               cancel_delayed_work_sync(&dev->link_work);
        }
        mutex_lock(&dev->link_lock);
        emac_netif_stop(dev);
index acbdab3d66caa70081e30b87f41e5e82c7d88b33..73a3e0d93237c97127e4eff1f31c52b4915f1119 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/phy.h>
 #include <linux/workqueue.h>
 #include <linux/of_mdio.h>
+#include <linux/of_net.h>
 #include <linux/of_platform.h>
 
 #include <asm/uaccess.h>
index 43307bd42a697c3bad30ee69a89e573a07146f48..6107304cb94c5e7050cda334d6eaa142218159d3 100644 (file)
@@ -1207,7 +1207,6 @@ static void housekeeping_enable(struct zd_mac *mac)
 static void housekeeping_disable(struct zd_mac *mac)
 {
        dev_dbg_f(zd_mac_dev(mac), "\n");
-       cancel_rearming_delayed_workqueue(zd_workqueue,
-               &mac->housekeeping.link_led_work);
+       cancel_delayed_work_sync(&mac->housekeeping.link_led_work);
        zd_chip_control_leds(&mac->chip, ZD_LED_OFF);
 }
index de6c3086d232b64eab460764b3407edba021a328..cad66ce1640b97069ce25b6c8539feadd353762a 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/of_mdio.h>
+#include <linux/of_net.h>
 #include <linux/phy.h>
 
 #define DRIVER_NAME "xilinx_emaclite"
index aa675ebd8eb3cd9636de7b69add0cfe73a134995..3c6e100a3ad042d998e9fcf3085ae476cf83443e 100644 (file)
@@ -19,6 +19,10 @@ config OF_FLATTREE
        bool
        select DTC
 
+config OF_EARLY_FLATTREE
+       bool
+       select OF_FLATTREE
+
 config OF_PROMTREE
        bool
 
@@ -49,6 +53,10 @@ config OF_I2C
        help
          OpenFirmware I2C accessors
 
+config OF_NET
+       depends on NETDEVICES
+       def_bool y
+
 config OF_SPI
        def_tristate SPI
        depends on SPI && !SPARC
index 7888155bea08dacb3317c0d25cc66a34a0d952ed..3ab21a0a4907defc5c3470f40c1d0ed74d6db731 100644 (file)
@@ -6,5 +6,6 @@ obj-$(CONFIG_OF_IRQ)    += irq.o
 obj-$(CONFIG_OF_DEVICE) += device.o platform.o
 obj-$(CONFIG_OF_GPIO)   += gpio.o
 obj-$(CONFIG_OF_I2C)   += of_i2c.o
+obj-$(CONFIG_OF_NET)   += of_net.o
 obj-$(CONFIG_OF_SPI)   += of_spi.o
 obj-$(CONFIG_OF_MDIO)  += of_mdio.o
index 3a1c7e70b192a014088649fb6a275154fb1f9b9c..b4559c58c0955a63b7c10bedfba400f2c0da2d3a 100644 (file)
                        (ns) > 0)
 
 static struct of_bus *of_match_bus(struct device_node *np);
-static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
-                                   u64 size, unsigned int flags,
+static int __of_address_to_resource(struct device_node *dev,
+               const __be32 *addrp, u64 size, unsigned int flags,
                                    struct resource *r);
 
 /* Debug utility */
 #ifdef DEBUG
-static void of_dump_addr(const char *s, const u32 *addr, int na)
+static void of_dump_addr(const char *s, const __be32 *addr, int na)
 {
        printk(KERN_DEBUG "%s", s);
        while (na--)
@@ -26,7 +26,7 @@ static void of_dump_addr(const char *s, const u32 *addr, int na)
        printk("\n");
 }
 #else
-static void of_dump_addr(const char *s, const u32 *addr, int na) { }
+static void of_dump_addr(const char *s, const __be32 *addr, int na) { }
 #endif
 
 /* Callbacks for bus specific translators */
@@ -36,10 +36,10 @@ struct of_bus {
        int             (*match)(struct device_node *parent);
        void            (*count_cells)(struct device_node *child,
                                       int *addrc, int *sizec);
-       u64             (*map)(u32 *addr, const u32 *range,
+       u64             (*map)(u32 *addr, const __be32 *range,
                                int na, int ns, int pna);
        int             (*translate)(u32 *addr, u64 offset, int na);
-       unsigned int    (*get_flags)(const u32 *addr);
+       unsigned int    (*get_flags)(const __be32 *addr);
 };
 
 /*
@@ -55,7 +55,7 @@ static void of_bus_default_count_cells(struct device_node *dev,
                *sizec = of_n_size_cells(dev);
 }
 
-static u64 of_bus_default_map(u32 *addr, const u32 *range,
+static u64 of_bus_default_map(u32 *addr, const __be32 *range,
                int na, int ns, int pna)
 {
        u64 cp, s, da;
@@ -85,7 +85,7 @@ static int of_bus_default_translate(u32 *addr, u64 offset, int na)
        return 0;
 }
 
-static unsigned int of_bus_default_get_flags(const u32 *addr)
+static unsigned int of_bus_default_get_flags(const __be32 *addr)
 {
        return IORESOURCE_MEM;
 }
@@ -110,10 +110,10 @@ static void of_bus_pci_count_cells(struct device_node *np,
                *sizec = 2;
 }
 
-static unsigned int of_bus_pci_get_flags(const u32 *addr)
+static unsigned int of_bus_pci_get_flags(const __be32 *addr)
 {
        unsigned int flags = 0;
-       u32 w = addr[0];
+       u32 w = be32_to_cpup(addr);
 
        switch((w >> 24) & 0x03) {
        case 0x01:
@@ -129,7 +129,8 @@ static unsigned int of_bus_pci_get_flags(const u32 *addr)
        return flags;
 }
 
-static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+static u64 of_bus_pci_map(u32 *addr, const __be32 *range, int na, int ns,
+               int pna)
 {
        u64 cp, s, da;
        unsigned int af, rf;
@@ -160,7 +161,7 @@ static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
        return of_bus_default_translate(addr + 1, offset, na - 1);
 }
 
-const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
+const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
                        unsigned int *flags)
 {
        const __be32 *prop;
@@ -207,7 +208,7 @@ EXPORT_SYMBOL(of_get_pci_address);
 int of_pci_address_to_resource(struct device_node *dev, int bar,
                               struct resource *r)
 {
-       const u32       *addrp;
+       const __be32    *addrp;
        u64             size;
        unsigned int    flags;
 
@@ -237,12 +238,13 @@ static void of_bus_isa_count_cells(struct device_node *child,
                *sizec = 1;
 }
 
-static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+static u64 of_bus_isa_map(u32 *addr, const __be32 *range, int na, int ns,
+               int pna)
 {
        u64 cp, s, da;
 
        /* Check address type match */
-       if ((addr[0] ^ range[0]) & 0x00000001)
+       if ((addr[0] ^ range[0]) & cpu_to_be32(1))
                return OF_BAD_ADDR;
 
        /* Read address values, skipping high cell */
@@ -264,10 +266,10 @@ static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
        return of_bus_default_translate(addr + 1, offset, na - 1);
 }
 
-static unsigned int of_bus_isa_get_flags(const u32 *addr)
+static unsigned int of_bus_isa_get_flags(const __be32 *addr)
 {
        unsigned int flags = 0;
-       u32 w = addr[0];
+       u32 w = be32_to_cpup(addr);
 
        if (w & 1)
                flags |= IORESOURCE_IO;
@@ -330,7 +332,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
                            struct of_bus *pbus, u32 *addr,
                            int na, int ns, int pna, const char *rprop)
 {
-       const u32 *ranges;
+       const __be32 *ranges;
        unsigned int rlen;
        int rone;
        u64 offset = OF_BAD_ADDR;
@@ -398,7 +400,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
  * that can be mapped to a cpu physical address). This is not really specified
  * that way, but this is traditionally the way IBM at least do things
  */
-u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
+u64 __of_translate_address(struct device_node *dev, const __be32 *in_addr,
                           const char *rprop)
 {
        struct device_node *parent = NULL;
@@ -475,22 +477,22 @@ u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
        return result;
 }
 
-u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
+u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
 {
        return __of_translate_address(dev, in_addr, "ranges");
 }
 EXPORT_SYMBOL(of_translate_address);
 
-u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr)
+u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
 {
        return __of_translate_address(dev, in_addr, "dma-ranges");
 }
 EXPORT_SYMBOL(of_translate_dma_address);
 
-const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
+const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
                    unsigned int *flags)
 {
-       const u32 *prop;
+       const __be32 *prop;
        unsigned int psize;
        struct device_node *parent;
        struct of_bus *bus;
@@ -525,8 +527,8 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
 }
 EXPORT_SYMBOL(of_get_address);
 
-static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
-                                   u64 size, unsigned int flags,
+static int __of_address_to_resource(struct device_node *dev,
+               const __be32 *addrp, u64 size, unsigned int flags,
                                    struct resource *r)
 {
        u64 taddr;
@@ -564,7 +566,7 @@ static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
 int of_address_to_resource(struct device_node *dev, int index,
                           struct resource *r)
 {
-       const u32       *addrp;
+       const __be32    *addrp;
        u64             size;
        unsigned int    flags;
 
index c1360e02f9212de87d1ce7680153d0058720a11b..c787c3d95c600eb51955dcb4d2e64dca88d559ba 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/initrd.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/slab.h>
 
 #ifdef CONFIG_PPC
 #include <asm/machdep.h>
 
 #include <asm/page.h>
 
-int __initdata dt_root_addr_cells;
-int __initdata dt_root_size_cells;
-
-struct boot_param_header *initial_boot_params;
-
-char *find_flat_dt_string(u32 offset)
+char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
 {
-       return ((char *)initial_boot_params) +
-               be32_to_cpu(initial_boot_params->off_dt_strings) + offset;
-}
-
-/**
- * of_scan_flat_dt - scan flattened tree blob and call callback on each.
- * @it: callback function
- * @data: context data pointer
- *
- * This function is used to scan the flattened device-tree, it is
- * used to extract the memory information at boot before we can
- * unflatten the tree
- */
-int __init of_scan_flat_dt(int (*it)(unsigned long node,
-                                    const char *uname, int depth,
-                                    void *data),
-                          void *data)
-{
-       unsigned long p = ((unsigned long)initial_boot_params) +
-               be32_to_cpu(initial_boot_params->off_dt_struct);
-       int rc = 0;
-       int depth = -1;
-
-       do {
-               u32 tag = be32_to_cpup((__be32 *)p);
-               char *pathp;
-
-               p += 4;
-               if (tag == OF_DT_END_NODE) {
-                       depth--;
-                       continue;
-               }
-               if (tag == OF_DT_NOP)
-                       continue;
-               if (tag == OF_DT_END)
-                       break;
-               if (tag == OF_DT_PROP) {
-                       u32 sz = be32_to_cpup((__be32 *)p);
-                       p += 8;
-                       if (be32_to_cpu(initial_boot_params->version) < 0x10)
-                               p = ALIGN(p, sz >= 8 ? 8 : 4);
-                       p += sz;
-                       p = ALIGN(p, 4);
-                       continue;
-               }
-               if (tag != OF_DT_BEGIN_NODE) {
-                       pr_err("Invalid tag %x in flat device tree!\n", tag);
-                       return -EINVAL;
-               }
-               depth++;
-               pathp = (char *)p;
-               p = ALIGN(p + strlen(pathp) + 1, 4);
-               if ((*pathp) == '/') {
-                       char *lp, *np;
-                       for (lp = NULL, np = pathp; *np; np++)
-                               if ((*np) == '/')
-                                       lp = np+1;
-                       if (lp != NULL)
-                               pathp = lp;
-               }
-               rc = it(p, pathp, depth, data);
-               if (rc != 0)
-                       break;
-       } while (1);
-
-       return rc;
+       return ((char *)blob) +
+               be32_to_cpu(blob->off_dt_strings) + offset;
 }
 
 /**
- * of_get_flat_dt_root - find the root node in the flat blob
+ * of_fdt_get_property - Given a node in the given flat blob, return
+ * the property ptr
  */
-unsigned long __init of_get_flat_dt_root(void)
-{
-       unsigned long p = ((unsigned long)initial_boot_params) +
-               be32_to_cpu(initial_boot_params->off_dt_struct);
-
-       while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
-               p += 4;
-       BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
-       p += 4;
-       return ALIGN(p + strlen((char *)p) + 1, 4);
-}
-
-/**
- * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
- *
- * This function can be used within scan_flattened_dt callback to get
- * access to properties
- */
-void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
-                                unsigned long *size)
+void *of_fdt_get_property(struct boot_param_header *blob,
+                      unsigned long node, const char *name,
+                      unsigned long *size)
 {
        unsigned long p = node;
 
@@ -137,10 +54,10 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
                sz = be32_to_cpup((__be32 *)p);
                noff = be32_to_cpup((__be32 *)(p + 4));
                p += 8;
-               if (be32_to_cpu(initial_boot_params->version) < 0x10)
+               if (be32_to_cpu(blob->version) < 0x10)
                        p = ALIGN(p, sz >= 8 ? 8 : 4);
 
-               nstr = find_flat_dt_string(noff);
+               nstr = of_fdt_get_string(blob, noff);
                if (nstr == NULL) {
                        pr_warning("Can't find property index name !\n");
                        return NULL;
@@ -156,21 +73,28 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
 }
 
 /**
- * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
+ * of_fdt_is_compatible - Return true if given node from the given blob has
+ * compat in its compatible list
+ * @blob: A device tree blob
  * @node: node to test
  * @compat: compatible string to compare with compatible list.
+ *
+ * On match, returns a non-zero value with smaller values returned for more
+ * specific compatible values.
  */
-int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
+int of_fdt_is_compatible(struct boot_param_header *blob,
+                     unsigned long node, const char *compat)
 {
        const char *cp;
-       unsigned long cplen, l;
+       unsigned long cplen, l, score = 0;
 
-       cp = of_get_flat_dt_prop(node, "compatible", &cplen);
+       cp = of_fdt_get_property(blob, node, "compatible", &cplen);
        if (cp == NULL)
                return 0;
        while (cplen > 0) {
+               score++;
                if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
+                       return score;
                l = strlen(cp) + 1;
                cp += l;
                cplen -= l;
@@ -179,7 +103,28 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
        return 0;
 }
 
-static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
+/**
+ * of_fdt_match - Return true if node matches a list of compatible values
+ */
+int of_fdt_match(struct boot_param_header *blob, unsigned long node,
+                 const char **compat)
+{
+       unsigned int tmp, score = 0;
+
+       if (!compat)
+               return 0;
+
+       while (*compat) {
+               tmp = of_fdt_is_compatible(blob, node, *compat);
+               if (tmp && (score == 0 || (tmp < score)))
+                       score = tmp;
+               compat++;
+       }
+
+       return score;
+}
+
+static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
                                       unsigned long align)
 {
        void *res;
@@ -193,16 +138,18 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
 
 /**
  * unflatten_dt_node - Alloc and populate a device_node from the flat tree
+ * @blob: The parent device tree blob
  * @p: pointer to node in flat tree
  * @dad: Parent struct device_node
  * @allnextpp: pointer to ->allnext from last allocated device_node
  * @fpsize: Size of the node path up at the current depth.
  */
-unsigned long __init unflatten_dt_node(unsigned long mem,
-                                       unsigned long *p,
-                                       struct device_node *dad,
-                                       struct device_node ***allnextpp,
-                                       unsigned long fpsize)
+unsigned long unflatten_dt_node(struct boot_param_header *blob,
+                               unsigned long mem,
+                               unsigned long *p,
+                               struct device_node *dad,
+                               struct device_node ***allnextpp,
+                               unsigned long fpsize)
 {
        struct device_node *np;
        struct property *pp, **prev_pp = NULL;
@@ -298,10 +245,10 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
                sz = be32_to_cpup((__be32 *)(*p));
                noff = be32_to_cpup((__be32 *)((*p) + 4));
                *p += 8;
-               if (be32_to_cpu(initial_boot_params->version) < 0x10)
+               if (be32_to_cpu(blob->version) < 0x10)
                        *p = ALIGN(*p, sz >= 8 ? 8 : 4);
 
-               pname = find_flat_dt_string(noff);
+               pname = of_fdt_get_string(blob, noff);
                if (pname == NULL) {
                        pr_info("Can't find property name in list !\n");
                        break;
@@ -380,7 +327,8 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
                if (tag == OF_DT_NOP)
                        *p += 4;
                else
-                       mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
+                       mem = unflatten_dt_node(blob, mem, p, np, allnextpp,
+                                               fpsize);
                tag = be32_to_cpup((__be32 *)(*p));
        }
        if (tag != OF_DT_END_NODE) {
@@ -391,6 +339,211 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
        return mem;
 }
 
+/**
+ * __unflatten_device_tree - create tree of device_nodes from flat blob
+ *
+ * unflattens a device-tree, creating the
+ * tree of struct device_node. It also fills the "name" and "type"
+ * pointers of the nodes so the normal device-tree walking functions
+ * can be used.
+ * @blob: The blob to expand
+ * @mynodes: The device_node tree created by the call
+ * @dt_alloc: An allocator that provides a virtual address to memory
+ * for the resulting tree
+ */
+void __unflatten_device_tree(struct boot_param_header *blob,
+                            struct device_node **mynodes,
+                            void * (*dt_alloc)(u64 size, u64 align))
+{
+       unsigned long start, mem, size;
+       struct device_node **allnextp = mynodes;
+
+       pr_debug(" -> unflatten_device_tree()\n");
+
+       if (!blob) {
+               pr_debug("No device tree pointer\n");
+               return;
+       }
+
+       pr_debug("Unflattening device tree:\n");
+       pr_debug("magic: %08x\n", be32_to_cpu(blob->magic));
+       pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize));
+       pr_debug("version: %08x\n", be32_to_cpu(blob->version));
+
+       if (be32_to_cpu(blob->magic) != OF_DT_HEADER) {
+               pr_err("Invalid device tree blob header\n");
+               return;
+       }
+
+       /* First pass, scan for size */
+       start = ((unsigned long)blob) +
+               be32_to_cpu(blob->off_dt_struct);
+       size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
+       size = (size | 3) + 1;
+
+       pr_debug("  size is %lx, allocating...\n", size);
+
+       /* Allocate memory for the expanded device tree */
+       mem = (unsigned long)
+               dt_alloc(size + 4, __alignof__(struct device_node));
+
+       ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
+
+       pr_debug("  unflattening %lx...\n", mem);
+
+       /* Second pass, do actual unflattening */
+       start = ((unsigned long)blob) +
+               be32_to_cpu(blob->off_dt_struct);
+       unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
+       if (be32_to_cpup((__be32 *)start) != OF_DT_END)
+               pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
+       if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
+               pr_warning("End of tree marker overwritten: %08x\n",
+                          be32_to_cpu(((__be32 *)mem)[size / 4]));
+       *allnextp = NULL;
+
+       pr_debug(" <- unflatten_device_tree()\n");
+}
+
+static void *kernel_tree_alloc(u64 size, u64 align)
+{
+       return kzalloc(size, GFP_KERNEL);
+}
+
+/**
+ * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
+ *
+ * unflattens the device-tree passed by the firmware, creating the
+ * tree of struct device_node. It also fills the "name" and "type"
+ * pointers of the nodes so the normal device-tree walking functions
+ * can be used.
+ */
+void of_fdt_unflatten_tree(unsigned long *blob,
+                       struct device_node **mynodes)
+{
+       struct boot_param_header *device_tree =
+               (struct boot_param_header *)blob;
+       __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc);
+}
+EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
+
+/* Everything below here references initial_boot_params directly. */
+int __initdata dt_root_addr_cells;
+int __initdata dt_root_size_cells;
+
+struct boot_param_header *initial_boot_params;
+
+#ifdef CONFIG_OF_EARLY_FLATTREE
+
+/**
+ * of_scan_flat_dt - scan flattened tree blob and call callback on each.
+ * @it: callback function
+ * @data: context data pointer
+ *
+ * This function is used to scan the flattened device-tree, it is
+ * used to extract the memory information at boot before we can
+ * unflatten the tree
+ */
+int __init of_scan_flat_dt(int (*it)(unsigned long node,
+                                    const char *uname, int depth,
+                                    void *data),
+                          void *data)
+{
+       unsigned long p = ((unsigned long)initial_boot_params) +
+               be32_to_cpu(initial_boot_params->off_dt_struct);
+       int rc = 0;
+       int depth = -1;
+
+       do {
+               u32 tag = be32_to_cpup((__be32 *)p);
+               char *pathp;
+
+               p += 4;
+               if (tag == OF_DT_END_NODE) {
+                       depth--;
+                       continue;
+               }
+               if (tag == OF_DT_NOP)
+                       continue;
+               if (tag == OF_DT_END)
+                       break;
+               if (tag == OF_DT_PROP) {
+                       u32 sz = be32_to_cpup((__be32 *)p);
+                       p += 8;
+                       if (be32_to_cpu(initial_boot_params->version) < 0x10)
+                               p = ALIGN(p, sz >= 8 ? 8 : 4);
+                       p += sz;
+                       p = ALIGN(p, 4);
+                       continue;
+               }
+               if (tag != OF_DT_BEGIN_NODE) {
+                       pr_err("Invalid tag %x in flat device tree!\n", tag);
+                       return -EINVAL;
+               }
+               depth++;
+               pathp = (char *)p;
+               p = ALIGN(p + strlen(pathp) + 1, 4);
+               if ((*pathp) == '/') {
+                       char *lp, *np;
+                       for (lp = NULL, np = pathp; *np; np++)
+                               if ((*np) == '/')
+                                       lp = np+1;
+                       if (lp != NULL)
+                               pathp = lp;
+               }
+               rc = it(p, pathp, depth, data);
+               if (rc != 0)
+                       break;
+       } while (1);
+
+       return rc;
+}
+
+/**
+ * of_get_flat_dt_root - find the root node in the flat blob
+ */
+unsigned long __init of_get_flat_dt_root(void)
+{
+       unsigned long p = ((unsigned long)initial_boot_params) +
+               be32_to_cpu(initial_boot_params->off_dt_struct);
+
+       while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
+               p += 4;
+       BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
+       p += 4;
+       return ALIGN(p + strlen((char *)p) + 1, 4);
+}
+
+/**
+ * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
+ *
+ * This function can be used within scan_flattened_dt callback to get
+ * access to properties
+ */
+void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
+                                unsigned long *size)
+{
+       return of_fdt_get_property(initial_boot_params, node, name, size);
+}
+
+/**
+ * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
+ * @node: node to test
+ * @compat: compatible string to compare with compatible list.
+ */
+int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
+{
+       return of_fdt_is_compatible(initial_boot_params, node, compat);
+}
+
+/**
+ * of_flat_dt_match - Return true if node matches a list of compatible values
+ */
+int __init of_flat_dt_match(unsigned long node, const char **compat)
+{
+       return of_fdt_match(initial_boot_params, node, compat);
+}
+
 #ifdef CONFIG_BLK_DEV_INITRD
 /**
  * early_init_dt_check_for_initrd - Decode initrd location from flat tree
@@ -539,6 +692,12 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
        return 1;
 }
 
+static void *__init early_device_tree_alloc(u64 size, u64 align)
+{
+       unsigned long mem = early_init_dt_alloc_memory_arch(size, align);
+       return __va(mem);
+}
+
 /**
  * unflatten_device_tree - create tree of device_nodes from flat blob
  *
@@ -549,58 +708,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
  */
 void __init unflatten_device_tree(void)
 {
-       unsigned long start, mem, size;
-       struct device_node **allnextp = &allnodes;
-
-       pr_debug(" -> unflatten_device_tree()\n");
-
-       if (!initial_boot_params) {
-               pr_debug("No device tree pointer\n");
-               return;
-       }
-
-       pr_debug("Unflattening device tree:\n");
-       pr_debug("magic: %08x\n", be32_to_cpu(initial_boot_params->magic));
-       pr_debug("size: %08x\n", be32_to_cpu(initial_boot_params->totalsize));
-       pr_debug("version: %08x\n", be32_to_cpu(initial_boot_params->version));
-
-       if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
-               pr_err("Invalid device tree blob header\n");
-               return;
-       }
-
-       /* First pass, scan for size */
-       start = ((unsigned long)initial_boot_params) +
-               be32_to_cpu(initial_boot_params->off_dt_struct);
-       size = unflatten_dt_node(0, &start, NULL, NULL, 0);
-       size = (size | 3) + 1;
-
-       pr_debug("  size is %lx, allocating...\n", size);
-
-       /* Allocate memory for the expanded device tree */
-       mem = early_init_dt_alloc_memory_arch(size + 4,
-                       __alignof__(struct device_node));
-       mem = (unsigned long) __va(mem);
-
-       ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
-
-       pr_debug("  unflattening %lx...\n", mem);
-
-       /* Second pass, do actual unflattening */
-       start = ((unsigned long)initial_boot_params) +
-               be32_to_cpu(initial_boot_params->off_dt_struct);
-       unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
-       if (be32_to_cpup((__be32 *)start) != OF_DT_END)
-               pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
-       if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
-               pr_warning("End of tree marker overwritten: %08x\n",
-                          be32_to_cpu(((__be32 *)mem)[size / 4]));
-       *allnextp = NULL;
+       __unflatten_device_tree(initial_boot_params, &allnodes,
+                               early_device_tree_alloc);
 
        /* Get pointer to OF "/chosen" node for use everywhere */
        of_chosen = of_find_node_by_path("/chosen");
        if (of_chosen == NULL)
                of_chosen = of_find_node_by_path("/chosen@0");
-
-       pr_debug(" <- unflatten_device_tree()\n");
 }
+
+#endif /* CONFIG_OF_EARLY_FLATTREE */
index 1fce00eb421bfc68ae531136a240680b66db4635..dcd7857784f24373f673ca2d027cc6a4a06be590 100644 (file)
@@ -52,27 +52,35 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
 
        /* Loop over the child nodes and register a phy_device for each one */
        for_each_child_of_node(np, child) {
-               const __be32 *addr;
+               const __be32 *paddr;
+               u32 addr;
                int len;
 
                /* A PHY must have a reg property in the range [0-31] */
-               addr = of_get_property(child, "reg", &len);
-               if (!addr || len < sizeof(*addr) || *addr >= 32 || *addr < 0) {
+               paddr = of_get_property(child, "reg", &len);
+               if (!paddr || len < sizeof(*paddr)) {
                        dev_err(&mdio->dev, "%s has invalid PHY address\n",
                                child->full_name);
                        continue;
                }
 
+               addr = be32_to_cpup(paddr);
+               if (addr >= 32) {
+                       dev_err(&mdio->dev, "%s PHY address %i is too large\n",
+                               child->full_name, addr);
+                       continue;
+               }
+
                if (mdio->irq) {
-                       mdio->irq[*addr] = irq_of_parse_and_map(child, 0);
-                       if (!mdio->irq[*addr])
-                               mdio->irq[*addr] = PHY_POLL;
+                       mdio->irq[addr] = irq_of_parse_and_map(child, 0);
+                       if (!mdio->irq[addr])
+                               mdio->irq[addr] = PHY_POLL;
                }
 
-               phy = get_phy_device(mdio, be32_to_cpup(addr));
+               phy = get_phy_device(mdio, addr);
                if (!phy || IS_ERR(phy)) {
                        dev_err(&mdio->dev, "error probing PHY at address %i\n",
-                               *addr);
+                               addr);
                        continue;
                }
                phy_scan_fixups(phy);
@@ -91,7 +99,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
                }
 
                dev_dbg(&mdio->dev, "registered phy %s at address %i\n",
-                       child->name, *addr);
+                       child->name, addr);
        }
 
        return 0;
diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
new file mode 100644 (file)
index 0000000..86f334a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * OF helpers for network devices.
+ *
+ * This file is released under the GPLv2
+ *
+ * Initially copied out of arch/powerpc/kernel/prom_parse.c
+ */
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/of_net.h>
+
+/**
+ * Search the device tree for the best MAC address to use.  'mac-address' is
+ * checked first, because that is supposed to contain to "most recent" MAC
+ * address. If that isn't set, then 'local-mac-address' is checked next,
+ * because that is the default address.  If that isn't set, then the obsolete
+ * 'address' is checked, just in case we're using an old device tree.
+ *
+ * Note that the 'address' property is supposed to contain a virtual address of
+ * the register set, but some DTS files have redefined that property to be the
+ * MAC address.
+ *
+ * All-zero MAC addresses are rejected, because those could be properties that
+ * exist in the device tree, but were not set by U-Boot.  For example, the
+ * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
+ * addresses.  Some older U-Boots only initialized 'local-mac-address'.  In
+ * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
+ * but is all zeros.
+*/
+const void *of_get_mac_address(struct device_node *np)
+{
+       struct property *pp;
+
+       pp = of_find_property(np, "mac-address", NULL);
+       if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
+               return pp->value;
+
+       pp = of_find_property(np, "local-mac-address", NULL);
+       if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
+               return pp->value;
+
+       pp = of_find_property(np, "address", NULL);
+       if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
+               return pp->value;
+
+       return NULL;
+}
+EXPORT_SYMBOL(of_get_mac_address);
index 5b4a07f1220ed38d326e87591eef924b15d9e353..c01cd1ac7617d6a50596691748036c154143074a 100644 (file)
@@ -633,6 +633,9 @@ EXPORT_SYMBOL(of_device_alloc);
  * @np: pointer to node to create device for
  * @bus_id: name to assign device
  * @parent: Linux device model parent device.
+ *
+ * Returns pointer to created platform device, or NULL if a device was not
+ * registered.  Unavailable devices will not get registered.
  */
 struct platform_device *of_platform_device_create(struct device_node *np,
                                            const char *bus_id,
@@ -640,6 +643,9 @@ struct platform_device *of_platform_device_create(struct device_node *np,
 {
        struct platform_device *dev;
 
+       if (!of_device_is_available(np))
+               return NULL;
+
        dev = of_device_alloc(np, bus_id, parent);
        if (!dev)
                return NULL;
@@ -683,8 +689,9 @@ static int of_platform_bus_create(const struct device_node *bus,
                pr_debug("   create child: %s\n", child->full_name);
                dev = of_platform_device_create(child, NULL, parent);
                if (dev == NULL)
-                       rc = -ENOMEM;
-               else if (!of_match_node(matches, child))
+                       continue;
+
+               if (!of_match_node(matches, child))
                        continue;
                if (rc == 0) {
                        pr_debug("   and sub busses\n");
@@ -733,10 +740,9 @@ int of_platform_bus_probe(struct device_node *root,
        if (of_match_node(matches, root)) {
                pr_debug(" root match, create all sub devices\n");
                dev = of_platform_device_create(root, NULL, parent);
-               if (dev == NULL) {
-                       rc = -ENOMEM;
+               if (dev == NULL)
                        goto bail;
-               }
+
                pr_debug(" create all sub busses\n");
                rc = of_platform_bus_create(root, matches, &dev->dev);
                goto bail;
@@ -748,9 +754,9 @@ int of_platform_bus_probe(struct device_node *root,
                pr_debug("  match: %s\n", child->full_name);
                dev = of_platform_device_create(child, NULL, parent);
                if (dev == NULL)
-                       rc = -ENOMEM;
-               else
-                       rc = of_platform_bus_create(child, matches, &dev->dev);
+                       continue;
+
+               rc = of_platform_bus_create(child, matches, &dev->dev);
                if (rc) {
                        of_node_put(child);
                        break;
index bab52047baa84101d2448a06b617381b21918444..7722108e78df4e9f5294aa5ab337f58af491f1ac 100644 (file)
@@ -36,7 +36,6 @@
 #define _ACPIPHP_H
 
 #include <linux/acpi.h>
-#include <linux/kobject.h>
 #include <linux/mutex.h>
 #include <linux/pci_hotplug.h>
 
index 2ea9cf1a8d02ec2fa2785f9493610f392a6b7be4..b283bbea6d24ad4132844694ae68351ff920e28f 100644 (file)
@@ -24,7 +24,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/kobject.h>
 #include <linux/sysfs.h>
 #include <linux/pci.h>
 #include <linux/string.h>
index b3c01c16a1640773ade9a1d09b813e9356c30c8b..e7f89785beefa6114e8afc0136265bdbc69f8c7d 100644 (file)
@@ -580,10 +580,8 @@ static int ds2760_battery_remove(struct platform_device *pdev)
 {
        struct ds2760_device_info *di = platform_get_drvdata(pdev);
 
-       cancel_rearming_delayed_workqueue(di->monitor_wqueue,
-                                         &di->monitor_work);
-       cancel_rearming_delayed_workqueue(di->monitor_wqueue,
-                                         &di->set_charged_work);
+       cancel_delayed_work_sync(&di->monitor_work);
+       cancel_delayed_work_sync(&di->set_charged_work);
        destroy_workqueue(di->monitor_wqueue);
        power_supply_unregister(&di->bat);
        kfree(di);
index 2a10cd361181292f9d6bbef7ef38cda9772c839b..36cf402c06772b6b34a7d5dd1c042c46cadd8ad2 100644 (file)
@@ -730,8 +730,7 @@ static __devinit int probe(int irq, struct device *dev)
 power_reg_failed_1:
        power_supply_unregister(&pbi->batt);
 power_reg_failed:
-       cancel_rearming_delayed_workqueue(pbi->monitor_wqueue,
-                                               &pbi->monitor_battery);
+       cancel_delayed_work_sync(&pbi->monitor_battery);
 requestirq_failed:
        destroy_workqueue(pbi->monitor_wqueue);
 wqueue_failed:
@@ -760,8 +759,7 @@ static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)
        struct pmic_power_module_info *pbi = dev_get_drvdata(&pdev->dev);
 
        free_irq(pbi->irq, pbi);
-       cancel_rearming_delayed_workqueue(pbi->monitor_wqueue,
-                                       &pbi->monitor_battery);
+       cancel_delayed_work_sync(&pbi->monitor_battery);
        destroy_workqueue(pbi->monitor_wqueue);
 
        power_supply_unregister(&pbi->usb);
index 62227cd5241053e14171c7ad2ab4daf2089a5db2..0cc0984d155b85109477e78254f91da4f6210e92 100644 (file)
@@ -104,7 +104,7 @@ static int clear_uie(struct rtc_device *rtc)
                }
                if (rtc->uie_task_active) {
                        spin_unlock_irq(&rtc->irq_lock);
-                       flush_scheduled_work();
+                       flush_work_sync(&rtc->uie_task);
                        spin_lock_irq(&rtc->irq_lock);
                }
                rtc->uie_irq_active = 0;
index 48da85e97ca4c589fd068f7930c157cc2c3b8154..077af1d7b9e4b7ccc2641887823a99cc79ad7359 100644 (file)
@@ -813,7 +813,7 @@ static int __devexit ds1305_remove(struct spi_device *spi)
        if (spi->irq) {
                set_bit(FLAG_EXITING, &ds1305->flags);
                free_irq(spi->irq, ds1305);
-               flush_scheduled_work();
+               cancel_work_sync(&ds1305->work);
        }
 
        rtc_device_unregister(ds1305->rtc);
index 1f0007fd44314c5b65ffc39fde6df81cc568d492..47fb6357c346a111abd5c9f5215ebf6cd644ee87 100644 (file)
@@ -417,7 +417,7 @@ static int __devexit ds1374_remove(struct i2c_client *client)
                mutex_unlock(&ds1374->mutex);
 
                free_irq(client->irq, client);
-               flush_scheduled_work();
+               cancel_work_sync(&ds1374->work);
        }
 
        rtc_device_unregister(ds1374->rtc);
index 57063552d3b76c538a64f692631a284f0d16a8dc..23a9ee19764cb5358b87eb5c935474a82bbbae4f 100644 (file)
@@ -463,7 +463,7 @@ static int __devexit ds3232_remove(struct i2c_client *client)
                mutex_unlock(&ds3232->mutex);
 
                free_irq(client->irq, client);
-               flush_scheduled_work();
+               cancel_work_sync(&ds3232->work);
        }
 
        rtc_device_unregister(ds3232->rtc);
index 1146e3522d3cdc82b512fc751e4ac6adf03c0440..af32a62e12a82365cf2e796f4d66d961505f42aa 100644 (file)
@@ -650,7 +650,7 @@ static int __devexit rx8025_remove(struct i2c_client *client)
                mutex_unlock(lock);
 
                free_irq(client->irq, client);
-               flush_scheduled_work();
+               cancel_work_sync(&rx8025->work);
        }
 
        rx8025_sysfs_unregister(&client->dev);
index deff2c3361e407220c68caf7cae9e29ce665ac3c..fbe361fcd2c09437e49bc8be0b82c56f08739769 100644 (file)
@@ -24,6 +24,8 @@
 #include "tape_std.h"
 #include "tape_3590.h"
 
+static struct workqueue_struct *tape_3590_wq;
+
 /*
  * Pointer to debug area.
  */
@@ -613,7 +615,7 @@ tape_3590_schedule_work(struct tape_device *device, enum tape_op op)
        p->device = tape_get_device(device);
        p->op = op;
 
-       schedule_work(&p->work);
+       queue_work(tape_3590_wq, &p->work);
        return 0;
 }
 
@@ -1629,7 +1631,7 @@ fail_kmalloc:
 static void
 tape_3590_cleanup_device(struct tape_device *device)
 {
-       flush_scheduled_work();
+       flush_workqueue(tape_3590_wq);
        tape_std_unassign(device);
 
        kfree(device->discdata);
@@ -1733,11 +1735,17 @@ tape_3590_init(void)
 #endif
 
        DBF_EVENT(3, "3590 init\n");
+
+       tape_3590_wq = alloc_workqueue("tape_3590", 0, 0);
+       if (!tape_3590_wq)
+               return -ENOMEM;
+
        /* Register driver for 3590 tapes. */
        rc = ccw_driver_register(&tape_3590_driver);
-       if (rc)
+       if (rc) {
+               destroy_workqueue(tape_3590_wq);
                DBF_EVENT(3, "3590 init failed\n");
-       else
+       else
                DBF_EVENT(3, "3590 registered\n");
        return rc;
 }
@@ -1746,7 +1754,7 @@ static void
 tape_3590_exit(void)
 {
        ccw_driver_unregister(&tape_3590_driver);
-
+       destroy_workqueue(tape_3590_wq);
        debug_unregister(TAPE_DBF_AREA);
 }
 
index f0fa9ca5cb2cfe09fda7c4e31179e7b1b7a1d083..55d2d0f4eabc9cbd67a4a6fe1638305f883beb00 100644 (file)
@@ -264,7 +264,7 @@ cleanup_queue:
 void
 tapeblock_cleanup_device(struct tape_device *device)
 {
-       flush_scheduled_work();
+       flush_work_sync(&device->blk_data.requeue_task);
        tape_put_device(device);
 
        if (!device->blk_data.disk) {
index 707b7f48c232d78bd56dd44fee580921ad1169d9..9e32780c317f39e7f7d0cb3a7296b8292ebbc699 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <linux/kobject.h>
 #include <linux/kobj_map.h>
 #include <linux/cdev.h>
 
index f4e6cf3aceb86ac86233cd6cd00485312a945824..430f875006f22b8535d6c179268655e053528962 100644 (file)
@@ -619,7 +619,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
        s390_idle_check(regs, S390_lowcore.int_clock,
                        S390_lowcore.async_enter_timer);
        irq_enter();
-       __get_cpu_var(s390_idle).nohz_delay = 1;
+       __this_cpu_write(s390_idle.nohz_delay, 1);
        if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
                /* Serve timer interrupts first. */
                clock_comparator_work();
index a624f5af4320d4b5e7158d2be4032d1501eb5336..e8566224fe4b48f5e1751acbe344a91c0ca10452 100644 (file)
@@ -467,7 +467,7 @@ static int jsflash_init(void)
 
        node = prom_getchild(prom_root_node);
        node = prom_searchsiblings(node, "flash-memory");
-       if (node != 0 && node != -1) {
+       if (node != 0 && (s32)node != -1) {
                if (prom_getproperty(node, "reg",
                    (char *)&reg0, sizeof(reg0)) == -1) {
                        printk("jsflash: no \"reg\" property\n");
index de2e09e49a3eefaa23d120a413758c36f913dcad..d3c5905b22ec6202649800a37dddf13c154a3d71 100644 (file)
@@ -5748,7 +5748,7 @@ static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd,
        }
 
        if (ipr_is_gata(res) && res->sata_port)
-               return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap);
+               return ata_sas_queuecmd(scsi_cmd, res->sata_port->ap);
 
        ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
        ioarcb = &ipr_cmd->ioarcb;
index 29251fabecc65b50643a295bf3ca87c422f920d6..5815cbeb27a6a6caa5397b202f18d3ad015e0879 100644 (file)
@@ -211,8 +211,7 @@ static int sas_queuecommand_lck(struct scsi_cmnd *cmd,
                        unsigned long flags;
 
                        spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
-                       res = ata_sas_queuecmd(cmd, scsi_done,
-                                              dev->sata_dev.ap);
+                       res = ata_sas_queuecmd(cmd, dev->sata_dev.ap);
                        spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
                        goto out;
                }
index ec3c214598d089c31bf461e26c1f0b5fde06afbe..188aff6d263f05943a279a1c11137c918eb65374 100644 (file)
@@ -1412,7 +1412,7 @@ config SERIAL_NETX_CONSOLE
 
 config SERIAL_OF_PLATFORM
        tristate "Serial port on Open Firmware platform bus"
-       depends on PPC_OF || MICROBLAZE
+       depends on OF
        depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
        help
          If you have a PowerPC based system that has serial ports
index 17849dcb9adc7e0e5090231192eef1778faeb8bb..5c7abe4c94dd4360de8c3ac26b9efd74af4a9867 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/nwpserial.h>
 
index 3f5e387ed56486ba5c454f4a809a9a57d84d80d5..5f63c3b83828ea1db4c9e18cb2eb7a92b9611dc6 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
-#include <linux/kobject.h>
 #include <linux/sysdev.h>
 #include <linux/seq_file.h>
 #include <linux/err.h>
index 78f9fd02c1b27c3ebf0753e1d9a995212b96ba48..1906840c1113cb6505a87418f7d97d5c324d7ec7 100644 (file)
@@ -111,11 +111,14 @@ config SPI_COLDFIRE_QSPI
          will be called coldfire_qspi.
 
 config SPI_DAVINCI
-       tristate "SPI controller driver for DaVinci/DA8xx SoC's"
+       tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
        depends on SPI_MASTER && ARCH_DAVINCI
        select SPI_BITBANG
        help
-         SPI master controller for DaVinci and DA8xx SPI modules.
+         SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
+
+         This driver can also be built as a module. The module will be called
+         davinci_spi.
 
 config SPI_EP93XX
        tristate "Cirrus Logic EP93xx SPI controller"
@@ -267,12 +270,15 @@ config SPI_PPC4xx
 
 config SPI_PXA2XX
        tristate "PXA2xx SSP SPI master"
-       depends on ARCH_PXA && EXPERIMENTAL
-       select PXA_SSP
+       depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
+       select PXA_SSP if ARCH_PXA
        help
-         This enables using a PXA2xx SSP port as a SPI master controller.
-         The driver can be configured to use any SSP port and additional
-         documentation can be found a Documentation/spi/pxa2xx.
+         This enables using a PXA2xx or Sodaville SSP port as a SPI master
+         controller. The driver can be configured to use any SSP port and
+         additional documentation can be found a Documentation/spi/pxa2xx.
+
+config SPI_PXA2XX_PCI
+       def_bool SPI_PXA2XX && X86_32 && PCI
 
 config SPI_S3C24XX
        tristate "Samsung S3C24XX series SPI"
@@ -353,7 +359,6 @@ config SPI_XILINX
        tristate "Xilinx SPI controller common module"
        depends on HAS_IOMEM && EXPERIMENTAL
        select SPI_BITBANG
-       select SPI_XILINX_OF if (XILINX_VIRTEX || MICROBLAZE)
        help
          This exposes the SPI controller IP from the Xilinx EDK.
 
@@ -362,19 +367,6 @@ config SPI_XILINX
 
          Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
 
-config SPI_XILINX_OF
-       tristate "Xilinx SPI controller OF device"
-       depends on SPI_XILINX && (XILINX_VIRTEX || MICROBLAZE)
-       help
-         This is the OF driver for the SPI controller IP from the Xilinx EDK.
-
-config SPI_XILINX_PLTFM
-       tristate "Xilinx SPI controller platform device"
-       depends on SPI_XILINX
-       help
-         This is the platform driver for the SPI controller IP
-         from the Xilinx EDK.
-
 config SPI_NUC900
        tristate "Nuvoton NUC900 series SPI"
        depends on ARCH_W90X900 && EXPERIMENTAL
@@ -396,6 +388,10 @@ config SPI_DW_PCI
        tristate "PCI interface driver for DW SPI core"
        depends on SPI_DESIGNWARE && PCI
 
+config SPI_DW_MID_DMA
+       bool "DMA support for DW SPI controller on Intel Moorestown platform"
+       depends on SPI_DW_PCI && INTEL_MID_DMAC
+
 config SPI_DW_MMIO
        tristate "Memory-mapped io interface driver for DW SPI core"
        depends on SPI_DESIGNWARE && HAVE_CLK
index 8bc1a5abac1fea65c166ba1c1a15e4c63b25a05d..3a42463c92a4935c7b56019910c096c1780e587c 100644 (file)
@@ -17,13 +17,15 @@ obj-$(CONFIG_SPI_BUTTERFLY)         += spi_butterfly.o
 obj-$(CONFIG_SPI_COLDFIRE_QSPI)                += coldfire_qspi.o
 obj-$(CONFIG_SPI_DAVINCI)              += davinci_spi.o
 obj-$(CONFIG_SPI_DESIGNWARE)           += dw_spi.o
-obj-$(CONFIG_SPI_DW_PCI)               += dw_spi_pci.o
+obj-$(CONFIG_SPI_DW_PCI)               += dw_spi_midpci.o
+dw_spi_midpci-objs                     := dw_spi_pci.o dw_spi_mid.o
 obj-$(CONFIG_SPI_DW_MMIO)              += dw_spi_mmio.o
 obj-$(CONFIG_SPI_EP93XX)               += ep93xx_spi.o
 obj-$(CONFIG_SPI_GPIO)                 += spi_gpio.o
 obj-$(CONFIG_SPI_IMX)                  += spi_imx.o
 obj-$(CONFIG_SPI_LM70_LLP)             += spi_lm70llp.o
 obj-$(CONFIG_SPI_PXA2XX)               += pxa2xx_spi.o
+obj-$(CONFIG_SPI_PXA2XX_PCI)           += pxa2xx_spi_pci.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)           += omap_uwire.o
 obj-$(CONFIG_SPI_OMAP24XX)             += omap2_mcspi.o
 obj-$(CONFIG_SPI_OMAP_100K)            += omap_spi_100k.o
@@ -43,8 +45,6 @@ obj-$(CONFIG_SPI_TEGRA)                       += spi_tegra.o
 obj-$(CONFIG_SPI_TOPCLIFF_PCH)         += spi_topcliff_pch.o
 obj-$(CONFIG_SPI_TXX9)                 += spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)               += xilinx_spi.o
-obj-$(CONFIG_SPI_XILINX_OF)            += xilinx_spi_of.o
-obj-$(CONFIG_SPI_XILINX_PLTFM)         += xilinx_spi_pltfm.o
 obj-$(CONFIG_SPI_SH_SCI)               += spi_sh_sci.o
 obj-$(CONFIG_SPI_SH_MSIOF)             += spi_sh_msiof.o
 obj-$(CONFIG_SPI_STMP3XXX)             += spi_stmp.o
index fb3d1b31772d223e24840ae2ac2c1e18b224ef76..a2a5921c730a89007d19e7d5d3b1645e893f69ca 100644 (file)
 #define STATE_DONE                     ((void *) 2)
 #define STATE_ERROR                    ((void *) -1)
 
-/*
- * Queue State
- */
-#define QUEUE_RUNNING                  (0)
-#define QUEUE_STOPPED                  (1)
 /*
  * SSP State - Whether Enabled or Disabled
  */
@@ -344,7 +339,7 @@ struct vendor_data {
  * @lock: spinlock to syncronise access to driver data
  * @workqueue: a workqueue on which any spi_message request is queued
  * @busy: workqueue is busy
- * @run: workqueue is running
+ * @running: workqueue is running
  * @pump_transfers: Tasklet used in Interrupt Transfer mode
  * @cur_msg: Pointer to current spi_message being processed
  * @cur_transfer: Pointer to current spi_transfer
@@ -369,8 +364,8 @@ struct pl022 {
        struct work_struct              pump_messages;
        spinlock_t                      queue_lock;
        struct list_head                queue;
-       int                             busy;
-       int                             run;
+       bool                            busy;
+       bool                            running;
        /* Message transfer pump */
        struct tasklet_struct           pump_transfers;
        struct spi_message              *cur_msg;
@@ -782,9 +777,9 @@ static void *next_transfer(struct pl022 *pl022)
 static void unmap_free_dma_scatter(struct pl022 *pl022)
 {
        /* Unmap and free the SG tables */
-       dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+       dma_unmap_sg(pl022->dma_tx_channel->device->dev, pl022->sgt_tx.sgl,
                     pl022->sgt_tx.nents, DMA_TO_DEVICE);
-       dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+       dma_unmap_sg(pl022->dma_rx_channel->device->dev, pl022->sgt_rx.sgl,
                     pl022->sgt_rx.nents, DMA_FROM_DEVICE);
        sg_free_table(&pl022->sgt_rx);
        sg_free_table(&pl022->sgt_tx);
@@ -917,7 +912,7 @@ static int configure_dma(struct pl022 *pl022)
        };
        unsigned int pages;
        int ret;
-       int sglen;
+       int rx_sglen, tx_sglen;
        struct dma_chan *rxchan = pl022->dma_rx_channel;
        struct dma_chan *txchan = pl022->dma_tx_channel;
        struct dma_async_tx_descriptor *rxdesc;
@@ -956,7 +951,7 @@ static int configure_dma(struct pl022 *pl022)
                tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
                break;
        case WRITING_U32:
-               tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;;
+               tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
                break;
        }
 
@@ -991,20 +986,20 @@ static int configure_dma(struct pl022 *pl022)
                          pl022->cur_transfer->len, &pl022->sgt_tx);
 
        /* Map DMA buffers */
-       sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+       rx_sglen = dma_map_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
                           pl022->sgt_rx.nents, DMA_FROM_DEVICE);
-       if (!sglen)
+       if (!rx_sglen)
                goto err_rx_sgmap;
 
-       sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+       tx_sglen = dma_map_sg(txchan->device->dev, pl022->sgt_tx.sgl,
                           pl022->sgt_tx.nents, DMA_TO_DEVICE);
-       if (!sglen)
+       if (!tx_sglen)
                goto err_tx_sgmap;
 
        /* Send both scatterlists */
        rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
                                      pl022->sgt_rx.sgl,
-                                     pl022->sgt_rx.nents,
+                                     rx_sglen,
                                      DMA_FROM_DEVICE,
                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!rxdesc)
@@ -1012,7 +1007,7 @@ static int configure_dma(struct pl022 *pl022)
 
        txdesc = txchan->device->device_prep_slave_sg(txchan,
                                      pl022->sgt_tx.sgl,
-                                     pl022->sgt_tx.nents,
+                                     tx_sglen,
                                      DMA_TO_DEVICE,
                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!txdesc)
@@ -1040,10 +1035,10 @@ err_txdesc:
        txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
 err_rxdesc:
        rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
-       dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+       dma_unmap_sg(txchan->device->dev, pl022->sgt_tx.sgl,
                     pl022->sgt_tx.nents, DMA_TO_DEVICE);
 err_tx_sgmap:
-       dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+       dma_unmap_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
                     pl022->sgt_tx.nents, DMA_FROM_DEVICE);
 err_rx_sgmap:
        sg_free_table(&pl022->sgt_tx);
@@ -1460,8 +1455,8 @@ static void pump_messages(struct work_struct *work)
 
        /* Lock queue and check for queue work */
        spin_lock_irqsave(&pl022->queue_lock, flags);
-       if (list_empty(&pl022->queue) || pl022->run == QUEUE_STOPPED) {
-               pl022->busy = 0;
+       if (list_empty(&pl022->queue) || !pl022->running) {
+               pl022->busy = false;
                spin_unlock_irqrestore(&pl022->queue_lock, flags);
                return;
        }
@@ -1475,7 +1470,7 @@ static void pump_messages(struct work_struct *work)
            list_entry(pl022->queue.next, struct spi_message, queue);
 
        list_del_init(&pl022->cur_msg->queue);
-       pl022->busy = 1;
+       pl022->busy = true;
        spin_unlock_irqrestore(&pl022->queue_lock, flags);
 
        /* Initial message state */
@@ -1507,8 +1502,8 @@ static int __init init_queue(struct pl022 *pl022)
        INIT_LIST_HEAD(&pl022->queue);
        spin_lock_init(&pl022->queue_lock);
 
-       pl022->run = QUEUE_STOPPED;
-       pl022->busy = 0;
+       pl022->running = false;
+       pl022->busy = false;
 
        tasklet_init(&pl022->pump_transfers,
                        pump_transfers, (unsigned long)pl022);
@@ -1529,12 +1524,12 @@ static int start_queue(struct pl022 *pl022)
 
        spin_lock_irqsave(&pl022->queue_lock, flags);
 
-       if (pl022->run == QUEUE_RUNNING || pl022->busy) {
+       if (pl022->running || pl022->busy) {
                spin_unlock_irqrestore(&pl022->queue_lock, flags);
                return -EBUSY;
        }
 
-       pl022->run = QUEUE_RUNNING;
+       pl022->running = true;
        pl022->cur_msg = NULL;
        pl022->cur_transfer = NULL;
        pl022->cur_chip = NULL;
@@ -1566,7 +1561,8 @@ static int stop_queue(struct pl022 *pl022)
 
        if (!list_empty(&pl022->queue) || pl022->busy)
                status = -EBUSY;
-       else pl022->run = QUEUE_STOPPED;
+       else
+               pl022->running = false;
 
        spin_unlock_irqrestore(&pl022->queue_lock, flags);
 
@@ -1684,7 +1680,7 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
 
        spin_lock_irqsave(&pl022->queue_lock, flags);
 
-       if (pl022->run == QUEUE_STOPPED) {
+       if (!pl022->running) {
                spin_unlock_irqrestore(&pl022->queue_lock, flags);
                return -ESHUTDOWN;
        }
@@ -1693,7 +1689,7 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
        msg->state = STATE_START;
 
        list_add_tail(&msg->queue, &pl022->queue);
-       if (pl022->run == QUEUE_RUNNING && !pl022->busy)
+       if (pl022->running && !pl022->busy)
                queue_work(pl022->workqueue, &pl022->pump_messages);
 
        spin_unlock_irqrestore(&pl022->queue_lock, flags);
index b85090caf7cf57df0a596f131944a13d64588d70..6beab99bf95b82ceacada96d20117678995eeded 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009 Texas Instruments.
+ * Copyright (C) 2010 EF Johnson Technologies
  *
  * 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
 
 #define CS_DEFAULT     0xFF
 
-#define SPI_BUFSIZ     (SMP_CACHE_BYTES + 1)
-#define DAVINCI_DMA_DATA_TYPE_S8       0x01
-#define DAVINCI_DMA_DATA_TYPE_S16      0x02
-#define DAVINCI_DMA_DATA_TYPE_S32      0x04
-
 #define SPIFMT_PHASE_MASK      BIT(16)
 #define SPIFMT_POLARITY_MASK   BIT(17)
 #define SPIFMT_DISTIMER_MASK   BIT(18)
 #define SPIFMT_ODD_PARITY_MASK BIT(23)
 #define SPIFMT_WDELAY_MASK     0x3f000000u
 #define SPIFMT_WDELAY_SHIFT    24
-#define SPIFMT_CHARLEN_MASK    0x0000001Fu
-
-/* SPIGCR1 */
-#define SPIGCR1_SPIENA_MASK    0x01000000u
+#define SPIFMT_PRESCALE_SHIFT  8
 
 /* SPIPC0 */
 #define SPIPC0_DIFUN_MASK      BIT(11)         /* MISO */
 #define SPIPC0_DOFUN_MASK      BIT(10)         /* MOSI */
 #define SPIPC0_CLKFUN_MASK     BIT(9)          /* CLK */
 #define SPIPC0_SPIENA_MASK     BIT(8)          /* nREADY */
-#define SPIPC0_EN1FUN_MASK     BIT(1)
-#define SPIPC0_EN0FUN_MASK     BIT(0)
 
 #define SPIINT_MASKALL         0x0101035F
-#define SPI_INTLVL_1           0x000001FFu
-#define SPI_INTLVL_0           0x00000000u
+#define SPIINT_MASKINT         0x0000015F
+#define SPI_INTLVL_1           0x000001FF
+#define SPI_INTLVL_0           0x00000000
 
-/* SPIDAT1 */
-#define SPIDAT1_CSHOLD_SHIFT   28
-#define SPIDAT1_CSNR_SHIFT     16
+/* SPIDAT1 (upper 16 bit defines) */
+#define SPIDAT1_CSHOLD_MASK    BIT(12)
+
+/* SPIGCR1 */
 #define SPIGCR1_CLKMOD_MASK    BIT(1)
 #define SPIGCR1_MASTER_MASK     BIT(0)
+#define SPIGCR1_POWERDOWN_MASK BIT(8)
 #define SPIGCR1_LOOPBACK_MASK  BIT(16)
+#define SPIGCR1_SPIENA_MASK    BIT(24)
 
 /* SPIBUF */
 #define SPIBUF_TXFULL_MASK     BIT(29)
 #define SPIBUF_RXEMPTY_MASK    BIT(31)
 
+/* SPIDELAY */
+#define SPIDELAY_C2TDELAY_SHIFT 24
+#define SPIDELAY_C2TDELAY_MASK  (0xFF << SPIDELAY_C2TDELAY_SHIFT)
+#define SPIDELAY_T2CDELAY_SHIFT 16
+#define SPIDELAY_T2CDELAY_MASK  (0xFF << SPIDELAY_T2CDELAY_SHIFT)
+#define SPIDELAY_T2EDELAY_SHIFT 8
+#define SPIDELAY_T2EDELAY_MASK  (0xFF << SPIDELAY_T2EDELAY_SHIFT)
+#define SPIDELAY_C2EDELAY_SHIFT 0
+#define SPIDELAY_C2EDELAY_MASK  0xFF
+
 /* Error Masks */
 #define SPIFLG_DLEN_ERR_MASK           BIT(0)
 #define SPIFLG_TIMEOUT_MASK            BIT(1)
 #define SPIFLG_DESYNC_MASK             BIT(3)
 #define SPIFLG_BITERR_MASK             BIT(4)
 #define SPIFLG_OVRRUN_MASK             BIT(6)
-#define SPIFLG_RX_INTR_MASK            BIT(8)
-#define SPIFLG_TX_INTR_MASK            BIT(9)
 #define SPIFLG_BUF_INIT_ACTIVE_MASK    BIT(24)
-#define SPIFLG_MASK                    (SPIFLG_DLEN_ERR_MASK \
+#define SPIFLG_ERROR_MASK              (SPIFLG_DLEN_ERR_MASK \
                                | SPIFLG_TIMEOUT_MASK | SPIFLG_PARERR_MASK \
                                | SPIFLG_DESYNC_MASK | SPIFLG_BITERR_MASK \
-                               | SPIFLG_OVRRUN_MASK | SPIFLG_RX_INTR_MASK \
-                               | SPIFLG_TX_INTR_MASK \
-                               | SPIFLG_BUF_INIT_ACTIVE_MASK)
-
-#define SPIINT_DLEN_ERR_INTR   BIT(0)
-#define SPIINT_TIMEOUT_INTR    BIT(1)
-#define SPIINT_PARERR_INTR     BIT(2)
-#define SPIINT_DESYNC_INTR     BIT(3)
-#define SPIINT_BITERR_INTR     BIT(4)
-#define SPIINT_OVRRUN_INTR     BIT(6)
-#define SPIINT_RX_INTR         BIT(8)
-#define SPIINT_TX_INTR         BIT(9)
-#define SPIINT_DMA_REQ_EN      BIT(16)
-#define SPIINT_ENABLE_HIGHZ    BIT(24)
+                               | SPIFLG_OVRRUN_MASK)
 
-#define SPI_T2CDELAY_SHIFT     16
-#define SPI_C2TDELAY_SHIFT     24
+#define SPIINT_DMA_REQ_EN      BIT(16)
 
 /* SPI Controller registers */
 #define SPIGCR0                0x00
 #define SPILVL         0x0c
 #define SPIFLG         0x10
 #define SPIPC0         0x14
-#define SPIPC1         0x18
-#define SPIPC2         0x1c
-#define SPIPC3         0x20
-#define SPIPC4         0x24
-#define SPIPC5         0x28
-#define SPIPC6         0x2c
-#define SPIPC7         0x30
-#define SPIPC8         0x34
-#define SPIDAT0                0x38
 #define SPIDAT1                0x3c
 #define SPIBUF         0x40
-#define SPIEMU         0x44
 #define SPIDELAY       0x48
 #define SPIDEF         0x4c
 #define SPIFMT0                0x50
-#define SPIFMT1                0x54
-#define SPIFMT2                0x58
-#define SPIFMT3                0x5c
-#define TGINTVEC0      0x60
-#define TGINTVEC1      0x64
-
-struct davinci_spi_slave {
-       u32     cmd_to_write;
-       u32     clk_ctrl_to_write;
-       u32     bytes_per_word;
-       u8      active_cs;
-};
 
 /* We have 2 DMA channels per CS, one for RX and one for TX */
 struct davinci_spi_dma {
-       int                     dma_tx_channel;
-       int                     dma_rx_channel;
-       int                     dma_tx_sync_dev;
-       int                     dma_rx_sync_dev;
+       int                     tx_channel;
+       int                     rx_channel;
+       int                     dummy_param_slot;
        enum dma_event_q        eventq;
-
-       struct completion       dma_tx_completion;
-       struct completion       dma_rx_completion;
 };
 
 /* SPI Controller driver's private data. */
@@ -166,58 +129,63 @@ struct davinci_spi {
        u8                      version;
        resource_size_t         pbase;
        void __iomem            *base;
-       size_t                  region_size;
        u32                     irq;
        struct completion       done;
 
        const void              *tx;
        void                    *rx;
-       u8                      *tmp_buf;
-       int                     count;
-       struct davinci_spi_dma  *dma_channels;
-       struct                  davinci_spi_platform_data *pdata;
+#define SPI_TMP_BUFSZ  (SMP_CACHE_BYTES + 1)
+       u8                      rx_tmp_buf[SPI_TMP_BUFSZ];
+       int                     rcount;
+       int                     wcount;
+       struct davinci_spi_dma  dma;
+       struct davinci_spi_platform_data *pdata;
 
        void                    (*get_rx)(u32 rx_data, struct davinci_spi *);
        u32                     (*get_tx)(struct davinci_spi *);
 
-       struct davinci_spi_slave slave[SPI_MAX_CHIPSELECT];
+       u8                      bytes_per_word[SPI_MAX_CHIPSELECT];
 };
 
-static unsigned use_dma;
+static struct davinci_spi_config davinci_spi_default_cfg;
 
-static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *davinci_spi)
+static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *dspi)
 {
-       u8 *rx = davinci_spi->rx;
-
-       *rx++ = (u8)data;
-       davinci_spi->rx = rx;
+       if (dspi->rx) {
+               u8 *rx = dspi->rx;
+               *rx++ = (u8)data;
+               dspi->rx = rx;
+       }
 }
 
-static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *davinci_spi)
+static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *dspi)
 {
-       u16 *rx = davinci_spi->rx;
-
-       *rx++ = (u16)data;
-       davinci_spi->rx = rx;
+       if (dspi->rx) {
+               u16 *rx = dspi->rx;
+               *rx++ = (u16)data;
+               dspi->rx = rx;
+       }
 }
 
-static u32 davinci_spi_tx_buf_u8(struct davinci_spi *davinci_spi)
+static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi)
 {
-       u32 data;
-       const u8 *tx = davinci_spi->tx;
-
-       data = *tx++;
-       davinci_spi->tx = tx;
+       u32 data = 0;
+       if (dspi->tx) {
+               const u8 *tx = dspi->tx;
+               data = *tx++;
+               dspi->tx = tx;
+       }
        return data;
 }
 
-static u32 davinci_spi_tx_buf_u16(struct davinci_spi *davinci_spi)
+static u32 davinci_spi_tx_buf_u16(struct davinci_spi *dspi)
 {
-       u32 data;
-       const u16 *tx = davinci_spi->tx;
-
-       data = *tx++;
-       davinci_spi->tx = tx;
+       u32 data = 0;
+       if (dspi->tx) {
+               const u16 *tx = dspi->tx;
+               data = *tx++;
+               dspi->tx = tx;
+       }
        return data;
 }
 
@@ -237,54 +205,66 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits)
        iowrite32(v, addr);
 }
 
-static inline void set_fmt_bits(void __iomem *addr, u32 bits, int cs_num)
-{
-       set_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits);
-}
-
-static inline void clear_fmt_bits(void __iomem *addr, u32 bits, int cs_num)
-{
-       clear_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits);
-}
-
-static void davinci_spi_set_dma_req(const struct spi_device *spi, int enable)
-{
-       struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master);
-
-       if (enable)
-               set_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN);
-       else
-               clear_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN);
-}
-
 /*
  * Interface to control the chip select signal
  */
 static void davinci_spi_chipselect(struct spi_device *spi, int value)
 {
-       struct davinci_spi *davinci_spi;
+       struct davinci_spi *dspi;
        struct davinci_spi_platform_data *pdata;
-       u32 data1_reg_val = 0;
+       u8 chip_sel = spi->chip_select;
+       u16 spidat1 = CS_DEFAULT;
+       bool gpio_chipsel = false;
 
-       davinci_spi = spi_master_get_devdata(spi->master);
-       pdata = davinci_spi->pdata;
+       dspi = spi_master_get_devdata(spi->master);
+       pdata = dspi->pdata;
+
+       if (pdata->chip_sel && chip_sel < pdata->num_chipselect &&
+                               pdata->chip_sel[chip_sel] != SPI_INTERN_CS)
+               gpio_chipsel = true;
 
        /*
         * Board specific chip select logic decides the polarity and cs
         * line for the controller
         */
-       if (value == BITBANG_CS_INACTIVE) {
-               set_io_bits(davinci_spi->base + SPIDEF, CS_DEFAULT);
-
-               data1_reg_val |= CS_DEFAULT << SPIDAT1_CSNR_SHIFT;
-               iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
+       if (gpio_chipsel) {
+               if (value == BITBANG_CS_ACTIVE)
+                       gpio_set_value(pdata->chip_sel[chip_sel], 0);
+               else
+                       gpio_set_value(pdata->chip_sel[chip_sel], 1);
+       } else {
+               if (value == BITBANG_CS_ACTIVE) {
+                       spidat1 |= SPIDAT1_CSHOLD_MASK;
+                       spidat1 &= ~(0x1 << chip_sel);
+               }
 
-               while ((ioread32(davinci_spi->base + SPIBUF)
-                                       & SPIBUF_RXEMPTY_MASK) == 0)
-                       cpu_relax();
+               iowrite16(spidat1, dspi->base + SPIDAT1 + 2);
        }
 }
 
+/**
+ * davinci_spi_get_prescale - Calculates the correct prescale value
+ * @maxspeed_hz: the maximum rate the SPI clock can run at
+ *
+ * This function calculates the prescale value that generates a clock rate
+ * less than or equal to the specified maximum.
+ *
+ * Returns: calculated prescale - 1 for easy programming into SPI registers
+ * or negative error number if valid prescalar cannot be updated.
+ */
+static inline int davinci_spi_get_prescale(struct davinci_spi *dspi,
+                                                       u32 max_speed_hz)
+{
+       int ret;
+
+       ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz);
+
+       if (ret < 3 || ret > 256)
+               return -EINVAL;
+
+       return ret - 1;
+}
+
 /**
  * davinci_spi_setup_transfer - This functions will determine transfer method
  * @spi: spi device on which data transfer to be done
@@ -298,13 +278,15 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
                struct spi_transfer *t)
 {
 
-       struct davinci_spi *davinci_spi;
-       struct davinci_spi_platform_data *pdata;
+       struct davinci_spi *dspi;
+       struct davinci_spi_config *spicfg;
        u8 bits_per_word = 0;
-       u32 hz = 0, prescale = 0, clkspeed;
+       u32 hz = 0, spifmt = 0, prescale = 0;
 
-       davinci_spi = spi_master_get_devdata(spi->master);
-       pdata = davinci_spi->pdata;
+       dspi = spi_master_get_devdata(spi->master);
+       spicfg = (struct davinci_spi_config *)spi->controller_data;
+       if (!spicfg)
+               spicfg = &davinci_spi_default_cfg;
 
        if (t) {
                bits_per_word = t->bits_per_word;
@@ -320,111 +302,83 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
         * 8bit, 16bit or 32bit transfer
         */
        if (bits_per_word <= 8 && bits_per_word >= 2) {
-               davinci_spi->get_rx = davinci_spi_rx_buf_u8;
-               davinci_spi->get_tx = davinci_spi_tx_buf_u8;
-               davinci_spi->slave[spi->chip_select].bytes_per_word = 1;
+               dspi->get_rx = davinci_spi_rx_buf_u8;
+               dspi->get_tx = davinci_spi_tx_buf_u8;
+               dspi->bytes_per_word[spi->chip_select] = 1;
        } else if (bits_per_word <= 16 && bits_per_word >= 2) {
-               davinci_spi->get_rx = davinci_spi_rx_buf_u16;
-               davinci_spi->get_tx = davinci_spi_tx_buf_u16;
-               davinci_spi->slave[spi->chip_select].bytes_per_word = 2;
+               dspi->get_rx = davinci_spi_rx_buf_u16;
+               dspi->get_tx = davinci_spi_tx_buf_u16;
+               dspi->bytes_per_word[spi->chip_select] = 2;
        } else
                return -EINVAL;
 
        if (!hz)
                hz = spi->max_speed_hz;
 
-       clear_fmt_bits(davinci_spi->base, SPIFMT_CHARLEN_MASK,
-                       spi->chip_select);
-       set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f,
-                       spi->chip_select);
+       /* Set up SPIFMTn register, unique to this chipselect. */
 
-       clkspeed = clk_get_rate(davinci_spi->clk);
-       if (hz > clkspeed / 2)
-               prescale = 1 << 8;
-       if (hz < clkspeed / 256)
-               prescale = 255 << 8;
-       if (!prescale)
-               prescale = ((clkspeed / hz - 1) << 8) & 0x0000ff00;
+       prescale = davinci_spi_get_prescale(dspi, hz);
+       if (prescale < 0)
+               return prescale;
 
-       clear_fmt_bits(davinci_spi->base, 0x0000ff00, spi->chip_select);
-       set_fmt_bits(davinci_spi->base, prescale, spi->chip_select);
+       spifmt = (prescale << SPIFMT_PRESCALE_SHIFT) | (bits_per_word & 0x1f);
 
-       return 0;
-}
+       if (spi->mode & SPI_LSB_FIRST)
+               spifmt |= SPIFMT_SHIFTDIR_MASK;
 
-static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data)
-{
-       struct spi_device *spi = (struct spi_device *)data;
-       struct davinci_spi *davinci_spi;
-       struct davinci_spi_dma *davinci_spi_dma;
-       struct davinci_spi_platform_data *pdata;
+       if (spi->mode & SPI_CPOL)
+               spifmt |= SPIFMT_POLARITY_MASK;
 
-       davinci_spi = spi_master_get_devdata(spi->master);
-       davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]);
-       pdata = davinci_spi->pdata;
+       if (!(spi->mode & SPI_CPHA))
+               spifmt |= SPIFMT_PHASE_MASK;
 
-       if (ch_status == DMA_COMPLETE)
-               edma_stop(davinci_spi_dma->dma_rx_channel);
-       else
-               edma_clean_channel(davinci_spi_dma->dma_rx_channel);
+       /*
+        * Version 1 hardware supports two basic SPI modes:
+        *  - Standard SPI mode uses 4 pins, with chipselect
+        *  - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
+        *      (distinct from SPI_3WIRE, with just one data wire;
+        *      or similar variants without MOSI or without MISO)
+        *
+        * Version 2 hardware supports an optional handshaking signal,
+        * so it can support two more modes:
+        *  - 5 pin SPI variant is standard SPI plus SPI_READY
+        *  - 4 pin with enable is (SPI_READY | SPI_NO_CS)
+        */
 
-       complete(&davinci_spi_dma->dma_rx_completion);
-       /* We must disable the DMA RX request */
-       davinci_spi_set_dma_req(spi, 0);
-}
+       if (dspi->version == SPI_VERSION_2) {
 
-static void davinci_spi_dma_tx_callback(unsigned lch, u16 ch_status, void *data)
-{
-       struct spi_device *spi = (struct spi_device *)data;
-       struct davinci_spi *davinci_spi;
-       struct davinci_spi_dma *davinci_spi_dma;
-       struct davinci_spi_platform_data *pdata;
+               u32 delay = 0;
 
-       davinci_spi = spi_master_get_devdata(spi->master);
-       davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]);
-       pdata = davinci_spi->pdata;
+               spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT)
+                                                       & SPIFMT_WDELAY_MASK);
 
-       if (ch_status == DMA_COMPLETE)
-               edma_stop(davinci_spi_dma->dma_tx_channel);
-       else
-               edma_clean_channel(davinci_spi_dma->dma_tx_channel);
+               if (spicfg->odd_parity)
+                       spifmt |= SPIFMT_ODD_PARITY_MASK;
 
-       complete(&davinci_spi_dma->dma_tx_completion);
-       /* We must disable the DMA TX request */
-       davinci_spi_set_dma_req(spi, 0);
-}
+               if (spicfg->parity_enable)
+                       spifmt |= SPIFMT_PARITYENA_MASK;
 
-static int davinci_spi_request_dma(struct spi_device *spi)
-{
-       struct davinci_spi *davinci_spi;
-       struct davinci_spi_dma *davinci_spi_dma;
-       struct davinci_spi_platform_data *pdata;
-       struct device *sdev;
-       int r;
+               if (spicfg->timer_disable) {
+                       spifmt |= SPIFMT_DISTIMER_MASK;
+               } else {
+                       delay |= (spicfg->c2tdelay << SPIDELAY_C2TDELAY_SHIFT)
+                                               & SPIDELAY_C2TDELAY_MASK;
+                       delay |= (spicfg->t2cdelay << SPIDELAY_T2CDELAY_SHIFT)
+                                               & SPIDELAY_T2CDELAY_MASK;
+               }
 
-       davinci_spi = spi_master_get_devdata(spi->master);
-       davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
-       pdata = davinci_spi->pdata;
-       sdev = davinci_spi->bitbang.master->dev.parent;
+               if (spi->mode & SPI_READY) {
+                       spifmt |= SPIFMT_WAITENA_MASK;
+                       delay |= (spicfg->t2edelay << SPIDELAY_T2EDELAY_SHIFT)
+                                               & SPIDELAY_T2EDELAY_MASK;
+                       delay |= (spicfg->c2edelay << SPIDELAY_C2EDELAY_SHIFT)
+                                               & SPIDELAY_C2EDELAY_MASK;
+               }
 
-       r = edma_alloc_channel(davinci_spi_dma->dma_rx_sync_dev,
-                               davinci_spi_dma_rx_callback, spi,
-                               davinci_spi_dma->eventq);
-       if (r < 0) {
-               dev_dbg(sdev, "Unable to request DMA channel for SPI RX\n");
-               return -EAGAIN;
+               iowrite32(delay, dspi->base + SPIDELAY);
        }
-       davinci_spi_dma->dma_rx_channel = r;
-       r = edma_alloc_channel(davinci_spi_dma->dma_tx_sync_dev,
-                               davinci_spi_dma_tx_callback, spi,
-                               davinci_spi_dma->eventq);
-       if (r < 0) {
-               edma_free_channel(davinci_spi_dma->dma_rx_channel);
-               davinci_spi_dma->dma_rx_channel = -1;
-               dev_dbg(sdev, "Unable to request DMA channel for SPI TX\n");
-               return -EAGAIN;
-       }
-       davinci_spi_dma->dma_tx_channel = r;
+
+       iowrite32(spifmt, dspi->base + SPIFMT0);
 
        return 0;
 }
@@ -435,190 +389,40 @@ static int davinci_spi_request_dma(struct spi_device *spi)
  *
  * This functions sets the default transfer method.
  */
-
 static int davinci_spi_setup(struct spi_device *spi)
 {
-       int retval;
-       struct davinci_spi *davinci_spi;
-       struct davinci_spi_dma *davinci_spi_dma;
-       struct device *sdev;
+       int retval = 0;
+       struct davinci_spi *dspi;
+       struct davinci_spi_platform_data *pdata;
 
-       davinci_spi = spi_master_get_devdata(spi->master);
-       sdev = davinci_spi->bitbang.master->dev.parent;
+       dspi = spi_master_get_devdata(spi->master);
+       pdata = dspi->pdata;
 
        /* if bits per word length is zero then set it default 8 */
        if (!spi->bits_per_word)
                spi->bits_per_word = 8;
 
-       davinci_spi->slave[spi->chip_select].cmd_to_write = 0;
-
-       if (use_dma && davinci_spi->dma_channels) {
-               davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
-
-               if ((davinci_spi_dma->dma_rx_channel == -1)
-                               || (davinci_spi_dma->dma_tx_channel == -1)) {
-                       retval = davinci_spi_request_dma(spi);
-                       if (retval < 0)
-                               return retval;
-               }
-       }
-
-       /*
-        * SPI in DaVinci and DA8xx operate between
-        * 600 KHz and 50 MHz
-        */
-       if (spi->max_speed_hz < 600000 || spi->max_speed_hz > 50000000) {
-               dev_dbg(sdev, "Operating frequency is not in acceptable "
-                               "range\n");
-               return -EINVAL;
-       }
-
-       /*
-        * Set up SPIFMTn register, unique to this chipselect.
-        *
-        * NOTE: we could do all of these with one write.  Also, some
-        * of the "version 2" features are found in chips that don't
-        * support all of them...
-        */
-       if (spi->mode & SPI_LSB_FIRST)
-               set_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
-                               spi->chip_select);
-       else
-               clear_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
-                               spi->chip_select);
-
-       if (spi->mode & SPI_CPOL)
-               set_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
-                               spi->chip_select);
-       else
-               clear_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
-                               spi->chip_select);
+       if (!(spi->mode & SPI_NO_CS)) {
+               if ((pdata->chip_sel == NULL) ||
+                   (pdata->chip_sel[spi->chip_select] == SPI_INTERN_CS))
+                       set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
 
-       if (!(spi->mode & SPI_CPHA))
-               set_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
-                               spi->chip_select);
-       else
-               clear_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
-                               spi->chip_select);
-
-       /*
-        * Version 1 hardware supports two basic SPI modes:
-        *  - Standard SPI mode uses 4 pins, with chipselect
-        *  - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
-        *      (distinct from SPI_3WIRE, with just one data wire;
-        *      or similar variants without MOSI or without MISO)
-        *
-        * Version 2 hardware supports an optional handshaking signal,
-        * so it can support two more modes:
-        *  - 5 pin SPI variant is standard SPI plus SPI_READY
-        *  - 4 pin with enable is (SPI_READY | SPI_NO_CS)
-        */
-
-       if (davinci_spi->version == SPI_VERSION_2) {
-               clear_fmt_bits(davinci_spi->base, SPIFMT_WDELAY_MASK,
-                               spi->chip_select);
-               set_fmt_bits(davinci_spi->base,
-                               (davinci_spi->pdata->wdelay
-                                               << SPIFMT_WDELAY_SHIFT)
-                                       & SPIFMT_WDELAY_MASK,
-                               spi->chip_select);
-
-               if (davinci_spi->pdata->odd_parity)
-                       set_fmt_bits(davinci_spi->base,
-                                       SPIFMT_ODD_PARITY_MASK,
-                                       spi->chip_select);
-               else
-                       clear_fmt_bits(davinci_spi->base,
-                                       SPIFMT_ODD_PARITY_MASK,
-                                       spi->chip_select);
-
-               if (davinci_spi->pdata->parity_enable)
-                       set_fmt_bits(davinci_spi->base,
-                                       SPIFMT_PARITYENA_MASK,
-                                       spi->chip_select);
-               else
-                       clear_fmt_bits(davinci_spi->base,
-                                       SPIFMT_PARITYENA_MASK,
-                                       spi->chip_select);
-
-               if (davinci_spi->pdata->wait_enable)
-                       set_fmt_bits(davinci_spi->base,
-                                       SPIFMT_WAITENA_MASK,
-                                       spi->chip_select);
-               else
-                       clear_fmt_bits(davinci_spi->base,
-                                       SPIFMT_WAITENA_MASK,
-                                       spi->chip_select);
-
-               if (davinci_spi->pdata->timer_disable)
-                       set_fmt_bits(davinci_spi->base,
-                                       SPIFMT_DISTIMER_MASK,
-                                       spi->chip_select);
-               else
-                       clear_fmt_bits(davinci_spi->base,
-                                       SPIFMT_DISTIMER_MASK,
-                                       spi->chip_select);
        }
 
-       retval = davinci_spi_setup_transfer(spi, NULL);
-
-       return retval;
-}
-
-static void davinci_spi_cleanup(struct spi_device *spi)
-{
-       struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master);
-       struct davinci_spi_dma *davinci_spi_dma;
-
-       davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
-
-       if (use_dma && davinci_spi->dma_channels) {
-               davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
-
-               if ((davinci_spi_dma->dma_rx_channel != -1)
-                               && (davinci_spi_dma->dma_tx_channel != -1)) {
-                       edma_free_channel(davinci_spi_dma->dma_tx_channel);
-                       edma_free_channel(davinci_spi_dma->dma_rx_channel);
-               }
-       }
-}
-
-static int davinci_spi_bufs_prep(struct spi_device *spi,
-                                struct davinci_spi *davinci_spi)
-{
-       int op_mode = 0;
-
-       /*
-        * REVISIT  unless devices disagree about SPI_LOOP or
-        * SPI_READY (SPI_NO_CS only allows one device!), this
-        * should not need to be done before each message...
-        * optimize for both flags staying cleared.
-        */
-
-       op_mode = SPIPC0_DIFUN_MASK
-               | SPIPC0_DOFUN_MASK
-               | SPIPC0_CLKFUN_MASK;
-       if (!(spi->mode & SPI_NO_CS))
-               op_mode |= 1 << spi->chip_select;
        if (spi->mode & SPI_READY)
-               op_mode |= SPIPC0_SPIENA_MASK;
-
-       iowrite32(op_mode, davinci_spi->base + SPIPC0);
+               set_io_bits(dspi->base + SPIPC0, SPIPC0_SPIENA_MASK);
 
        if (spi->mode & SPI_LOOP)
-               set_io_bits(davinci_spi->base + SPIGCR1,
-                               SPIGCR1_LOOPBACK_MASK);
+               set_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK);
        else
-               clear_io_bits(davinci_spi->base + SPIGCR1,
-                               SPIGCR1_LOOPBACK_MASK);
+               clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK);
 
-       return 0;
+       return retval;
 }
 
-static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
-                                  int int_status)
+static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
 {
-       struct device *sdev = davinci_spi->bitbang.master->dev.parent;
+       struct device *sdev = dspi->bitbang.master->dev.parent;
 
        if (int_status & SPIFLG_TIMEOUT_MASK) {
                dev_dbg(sdev, "SPI Time-out Error\n");
@@ -633,7 +437,7 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
                return -EIO;
        }
 
-       if (davinci_spi->version == SPI_VERSION_2) {
+       if (dspi->version == SPI_VERSION_2) {
                if (int_status & SPIFLG_DLEN_ERR_MASK) {
                        dev_dbg(sdev, "SPI Data Length Error\n");
                        return -EIO;
@@ -646,10 +450,6 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
                        dev_dbg(sdev, "SPI Data Overrun error\n");
                        return -EIO;
                }
-               if (int_status & SPIFLG_TX_INTR_MASK) {
-                       dev_dbg(sdev, "SPI TX intr bit set\n");
-                       return -EIO;
-               }
                if (int_status & SPIFLG_BUF_INIT_ACTIVE_MASK) {
                        dev_dbg(sdev, "SPI Buffer Init Active\n");
                        return -EBUSY;
@@ -660,366 +460,339 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
 }
 
 /**
- * davinci_spi_bufs - functions which will handle transfer data
- * @spi: spi device on which data transfer to be done
- * @t: spi transfer in which transfer info is filled
+ * davinci_spi_process_events - check for and handle any SPI controller events
+ * @dspi: the controller data
  *
- * This function will put data to be transferred into data register
- * of SPI controller and then wait until the completion will be marked
- * by the IRQ Handler.
+ * This function will check the SPIFLG register and handle any events that are
+ * detected there
  */
-static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t)
+static int davinci_spi_process_events(struct davinci_spi *dspi)
 {
-       struct davinci_spi *davinci_spi;
-       int int_status, count, ret;
-       u8 conv, tmp;
-       u32 tx_data, data1_reg_val;
-       u32 buf_val, flg_val;
-       struct davinci_spi_platform_data *pdata;
-
-       davinci_spi = spi_master_get_devdata(spi->master);
-       pdata = davinci_spi->pdata;
-
-       davinci_spi->tx = t->tx_buf;
-       davinci_spi->rx = t->rx_buf;
-
-       /* convert len to words based on bits_per_word */
-       conv = davinci_spi->slave[spi->chip_select].bytes_per_word;
-       davinci_spi->count = t->len / conv;
-
-       INIT_COMPLETION(davinci_spi->done);
-
-       ret = davinci_spi_bufs_prep(spi, davinci_spi);
-       if (ret)
-               return ret;
-
-       /* Enable SPI */
-       set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
-
-       iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) |
-                       (pdata->t2cdelay << SPI_T2CDELAY_SHIFT),
-                       davinci_spi->base + SPIDELAY);
-
-       count = davinci_spi->count;
-       data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT;
-       tmp = ~(0x1 << spi->chip_select);
-
-       clear_io_bits(davinci_spi->base + SPIDEF, ~tmp);
-
-       data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT;
+       u32 buf, status, errors = 0, spidat1;
 
-       while ((ioread32(davinci_spi->base + SPIBUF)
-                               & SPIBUF_RXEMPTY_MASK) == 0)
-               cpu_relax();
+       buf = ioread32(dspi->base + SPIBUF);
 
-       /* Determine the command to execute READ or WRITE */
-       if (t->tx_buf) {
-               clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
+       if (dspi->rcount > 0 && !(buf & SPIBUF_RXEMPTY_MASK)) {
+               dspi->get_rx(buf & 0xFFFF, dspi);
+               dspi->rcount--;
+       }
 
-               while (1) {
-                       tx_data = davinci_spi->get_tx(davinci_spi);
+       status = ioread32(dspi->base + SPIFLG);
 
-                       data1_reg_val &= ~(0xFFFF);
-                       data1_reg_val |= (0xFFFF & tx_data);
+       if (unlikely(status & SPIFLG_ERROR_MASK)) {
+               errors = status & SPIFLG_ERROR_MASK;
+               goto out;
+       }
 
-                       buf_val = ioread32(davinci_spi->base + SPIBUF);
-                       if ((buf_val & SPIBUF_TXFULL_MASK) == 0) {
-                               iowrite32(data1_reg_val,
-                                               davinci_spi->base + SPIDAT1);
+       if (dspi->wcount > 0 && !(buf & SPIBUF_TXFULL_MASK)) {
+               spidat1 = ioread32(dspi->base + SPIDAT1);
+               dspi->wcount--;
+               spidat1 &= ~0xFFFF;
+               spidat1 |= 0xFFFF & dspi->get_tx(dspi);
+               iowrite32(spidat1, dspi->base + SPIDAT1);
+       }
 
-                               count--;
-                       }
-                       while (ioread32(davinci_spi->base + SPIBUF)
-                                       & SPIBUF_RXEMPTY_MASK)
-                               cpu_relax();
-
-                       /* getting the returned byte */
-                       if (t->rx_buf) {
-                               buf_val = ioread32(davinci_spi->base + SPIBUF);
-                               davinci_spi->get_rx(buf_val, davinci_spi);
-                       }
-                       if (count <= 0)
-                               break;
-               }
-       } else {
-               if (pdata->poll_mode) {
-                       while (1) {
-                               /* keeps the serial clock going */
-                               if ((ioread32(davinci_spi->base + SPIBUF)
-                                               & SPIBUF_TXFULL_MASK) == 0)
-                                       iowrite32(data1_reg_val,
-                                               davinci_spi->base + SPIDAT1);
-
-                               while (ioread32(davinci_spi->base + SPIBUF) &
-                                               SPIBUF_RXEMPTY_MASK)
-                                       cpu_relax();
-
-                               flg_val = ioread32(davinci_spi->base + SPIFLG);
-                               buf_val = ioread32(davinci_spi->base + SPIBUF);
-
-                               davinci_spi->get_rx(buf_val, davinci_spi);
-
-                               count--;
-                               if (count <= 0)
-                                       break;
-                       }
-               } else {        /* Receive in Interrupt mode */
-                       int i;
+out:
+       return errors;
+}
 
-                       for (i = 0; i < davinci_spi->count; i++) {
-                               set_io_bits(davinci_spi->base + SPIINT,
-                                               SPIINT_BITERR_INTR
-                                               | SPIINT_OVRRUN_INTR
-                                               | SPIINT_RX_INTR);
+static void davinci_spi_dma_callback(unsigned lch, u16 status, void *data)
+{
+       struct davinci_spi *dspi = data;
+       struct davinci_spi_dma *dma = &dspi->dma;
 
-                               iowrite32(data1_reg_val,
-                                               davinci_spi->base + SPIDAT1);
+       edma_stop(lch);
 
-                               while (ioread32(davinci_spi->base + SPIINT) &
-                                               SPIINT_RX_INTR)
-                                       cpu_relax();
-                       }
-                       iowrite32((data1_reg_val & 0x0ffcffff),
-                                       davinci_spi->base + SPIDAT1);
-               }
+       if (status == DMA_COMPLETE) {
+               if (lch == dma->rx_channel)
+                       dspi->rcount = 0;
+               if (lch == dma->tx_channel)
+                       dspi->wcount = 0;
        }
 
-       /*
-        * Check for bit error, desync error,parity error,timeout error and
-        * receive overflow errors
-        */
-       int_status = ioread32(davinci_spi->base + SPIFLG);
-
-       ret = davinci_spi_check_error(davinci_spi, int_status);
-       if (ret != 0)
-               return ret;
-
-       /* SPI Framework maintains the count only in bytes so convert back */
-       davinci_spi->count *= conv;
-
-       return t->len;
+       if ((!dspi->wcount && !dspi->rcount) || (status != DMA_COMPLETE))
+               complete(&dspi->done);
 }
 
-#define DAVINCI_DMA_DATA_TYPE_S8       0x01
-#define DAVINCI_DMA_DATA_TYPE_S16      0x02
-#define DAVINCI_DMA_DATA_TYPE_S32      0x04
-
-static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t)
+/**
+ * davinci_spi_bufs - functions which will handle transfer data
+ * @spi: spi device on which data transfer to be done
+ * @t: spi transfer in which transfer info is filled
+ *
+ * This function will put data to be transferred into data register
+ * of SPI controller and then wait until the completion will be marked
+ * by the IRQ Handler.
+ */
+static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
 {
-       struct davinci_spi *davinci_spi;
-       int int_status = 0;
-       int count, temp_count;
-       u8 conv = 1;
-       u8 tmp;
-       u32 data1_reg_val;
-       struct davinci_spi_dma *davinci_spi_dma;
-       int word_len, data_type, ret;
-       unsigned long tx_reg, rx_reg;
+       struct davinci_spi *dspi;
+       int data_type, ret;
+       u32 tx_data, spidat1;
+       u32 errors = 0;
+       struct davinci_spi_config *spicfg;
        struct davinci_spi_platform_data *pdata;
+       unsigned uninitialized_var(rx_buf_count);
        struct device *sdev;
 
-       davinci_spi = spi_master_get_devdata(spi->master);
-       pdata = davinci_spi->pdata;
-       sdev = davinci_spi->bitbang.master->dev.parent;
-
-       davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
-
-       tx_reg = (unsigned long)davinci_spi->pbase + SPIDAT1;
-       rx_reg = (unsigned long)davinci_spi->pbase + SPIBUF;
-
-       davinci_spi->tx = t->tx_buf;
-       davinci_spi->rx = t->rx_buf;
+       dspi = spi_master_get_devdata(spi->master);
+       pdata = dspi->pdata;
+       spicfg = (struct davinci_spi_config *)spi->controller_data;
+       if (!spicfg)
+               spicfg = &davinci_spi_default_cfg;
+       sdev = dspi->bitbang.master->dev.parent;
 
        /* convert len to words based on bits_per_word */
-       conv = davinci_spi->slave[spi->chip_select].bytes_per_word;
-       davinci_spi->count = t->len / conv;
-
-       INIT_COMPLETION(davinci_spi->done);
+       data_type = dspi->bytes_per_word[spi->chip_select];
 
-       init_completion(&davinci_spi_dma->dma_rx_completion);
-       init_completion(&davinci_spi_dma->dma_tx_completion);
+       dspi->tx = t->tx_buf;
+       dspi->rx = t->rx_buf;
+       dspi->wcount = t->len / data_type;
+       dspi->rcount = dspi->wcount;
 
-       word_len = conv * 8;
-
-       if (word_len <= 8)
-               data_type = DAVINCI_DMA_DATA_TYPE_S8;
-       else if (word_len <= 16)
-               data_type = DAVINCI_DMA_DATA_TYPE_S16;
-       else if (word_len <= 32)
-               data_type = DAVINCI_DMA_DATA_TYPE_S32;
-       else
-               return -EINVAL;
-
-       ret = davinci_spi_bufs_prep(spi, davinci_spi);
-       if (ret)
-               return ret;
+       spidat1 = ioread32(dspi->base + SPIDAT1);
 
-       /* Put delay val if required */
-       iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) |
-                       (pdata->t2cdelay << SPI_T2CDELAY_SHIFT),
-                       davinci_spi->base + SPIDELAY);
+       clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
+       set_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
 
-       count = davinci_spi->count;     /* the number of elements */
-       data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT;
+       INIT_COMPLETION(dspi->done);
 
-       /* CS default = 0xFF */
-       tmp = ~(0x1 << spi->chip_select);
+       if (spicfg->io_type == SPI_IO_TYPE_INTR)
+               set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
 
-       clear_io_bits(davinci_spi->base + SPIDEF, ~tmp);
-
-       data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT;
-
-       /* disable all interrupts for dma transfers */
-       clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
-       /* Disable SPI to write configuration bits in SPIDAT */
-       clear_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
-       iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
-       /* Enable SPI */
-       set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
-
-       while ((ioread32(davinci_spi->base + SPIBUF)
-                               & SPIBUF_RXEMPTY_MASK) == 0)
-               cpu_relax();
-
-
-       if (t->tx_buf) {
-               t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf, count,
-                               DMA_TO_DEVICE);
-               if (dma_mapping_error(&spi->dev, t->tx_dma)) {
-                       dev_dbg(sdev, "Unable to DMA map a %d bytes"
-                               " TX buffer\n", count);
-                       return -ENOMEM;
-               }
-               temp_count = count;
+       if (spicfg->io_type != SPI_IO_TYPE_DMA) {
+               /* start the transfer */
+               dspi->wcount--;
+               tx_data = dspi->get_tx(dspi);
+               spidat1 &= 0xFFFF0000;
+               spidat1 |= tx_data & 0xFFFF;
+               iowrite32(spidat1, dspi->base + SPIDAT1);
        } else {
-               /* We need TX clocking for RX transaction */
-               t->tx_dma = dma_map_single(&spi->dev,
-                               (void *)davinci_spi->tmp_buf, count + 1,
-                               DMA_TO_DEVICE);
-               if (dma_mapping_error(&spi->dev, t->tx_dma)) {
-                       dev_dbg(sdev, "Unable to DMA map a %d bytes"
-                               " TX tmp buffer\n", count);
-                       return -ENOMEM;
+               struct davinci_spi_dma *dma;
+               unsigned long tx_reg, rx_reg;
+               struct edmacc_param param;
+               void *rx_buf;
+
+               dma = &dspi->dma;
+
+               tx_reg = (unsigned long)dspi->pbase + SPIDAT1;
+               rx_reg = (unsigned long)dspi->pbase + SPIBUF;
+
+               /*
+                * Transmit DMA setup
+                *
+                * If there is transmit data, map the transmit buffer, set it
+                * as the source of data and set the source B index to data
+                * size. If there is no transmit data, set the transmit register
+                * as the source of data, and set the source B index to zero.
+                *
+                * The destination is always the transmit register itself. And
+                * the destination never increments.
+                */
+
+               if (t->tx_buf) {
+                       t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf,
+                                               dspi->wcount, DMA_TO_DEVICE);
+                       if (dma_mapping_error(&spi->dev, t->tx_dma)) {
+                               dev_dbg(sdev, "Unable to DMA map %d bytes"
+                                               "TX buffer\n", dspi->wcount);
+                               return -ENOMEM;
+                       }
                }
-               temp_count = count + 1;
-       }
 
-       edma_set_transfer_params(davinci_spi_dma->dma_tx_channel,
-                                       data_type, temp_count, 1, 0, ASYNC);
-       edma_set_dest(davinci_spi_dma->dma_tx_channel, tx_reg, INCR, W8BIT);
-       edma_set_src(davinci_spi_dma->dma_tx_channel, t->tx_dma, INCR, W8BIT);
-       edma_set_src_index(davinci_spi_dma->dma_tx_channel, data_type, 0);
-       edma_set_dest_index(davinci_spi_dma->dma_tx_channel, 0, 0);
-
-       if (t->rx_buf) {
-               /* initiate transaction */
-               iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
+               param.opt = TCINTEN | EDMA_TCC(dma->tx_channel);
+               param.src = t->tx_buf ? t->tx_dma : tx_reg;
+               param.a_b_cnt = dspi->wcount << 16 | data_type;
+               param.dst = tx_reg;
+               param.src_dst_bidx = t->tx_buf ? data_type : 0;
+               param.link_bcntrld = 0xffff;
+               param.src_dst_cidx = 0;
+               param.ccnt = 1;
+               edma_write_slot(dma->tx_channel, &param);
+               edma_link(dma->tx_channel, dma->dummy_param_slot);
+
+               /*
+                * Receive DMA setup
+                *
+                * If there is receive buffer, use it to receive data. If there
+                * is none provided, use a temporary receive buffer. Set the
+                * destination B index to 0 so effectively only one byte is used
+                * in the temporary buffer (address does not increment).
+                *
+                * The source of receive data is the receive data register. The
+                * source address never increments.
+                */
+
+               if (t->rx_buf) {
+                       rx_buf = t->rx_buf;
+                       rx_buf_count = dspi->rcount;
+               } else {
+                       rx_buf = dspi->rx_tmp_buf;
+                       rx_buf_count = sizeof(dspi->rx_tmp_buf);
+               }
 
-               t->rx_dma = dma_map_single(&spi->dev, (void *)t->rx_buf, count,
-                               DMA_FROM_DEVICE);
+               t->rx_dma = dma_map_single(&spi->dev, rx_buf, rx_buf_count,
+                                                       DMA_FROM_DEVICE);
                if (dma_mapping_error(&spi->dev, t->rx_dma)) {
                        dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n",
-                                       count);
-                       if (t->tx_buf != NULL)
-                               dma_unmap_single(NULL, t->tx_dma,
-                                                count, DMA_TO_DEVICE);
+                                                               rx_buf_count);
+                       if (t->tx_buf)
+                               dma_unmap_single(NULL, t->tx_dma, dspi->wcount,
+                                                               DMA_TO_DEVICE);
                        return -ENOMEM;
                }
-               edma_set_transfer_params(davinci_spi_dma->dma_rx_channel,
-                               data_type, count, 1, 0, ASYNC);
-               edma_set_src(davinci_spi_dma->dma_rx_channel,
-                               rx_reg, INCR, W8BIT);
-               edma_set_dest(davinci_spi_dma->dma_rx_channel,
-                               t->rx_dma, INCR, W8BIT);
-               edma_set_src_index(davinci_spi_dma->dma_rx_channel, 0, 0);
-               edma_set_dest_index(davinci_spi_dma->dma_rx_channel,
-                               data_type, 0);
-       }
 
-       if ((t->tx_buf) || (t->rx_buf))
-               edma_start(davinci_spi_dma->dma_tx_channel);
+               param.opt = TCINTEN | EDMA_TCC(dma->rx_channel);
+               param.src = rx_reg;
+               param.a_b_cnt = dspi->rcount << 16 | data_type;
+               param.dst = t->rx_dma;
+               param.src_dst_bidx = (t->rx_buf ? data_type : 0) << 16;
+               param.link_bcntrld = 0xffff;
+               param.src_dst_cidx = 0;
+               param.ccnt = 1;
+               edma_write_slot(dma->rx_channel, &param);
+
+               if (pdata->cshold_bug)
+                       iowrite16(spidat1 >> 16, dspi->base + SPIDAT1 + 2);
+
+               edma_start(dma->rx_channel);
+               edma_start(dma->tx_channel);
+               set_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
+       }
 
-       if (t->rx_buf)
-               edma_start(davinci_spi_dma->dma_rx_channel);
+       /* Wait for the transfer to complete */
+       if (spicfg->io_type != SPI_IO_TYPE_POLL) {
+               wait_for_completion_interruptible(&(dspi->done));
+       } else {
+               while (dspi->rcount > 0 || dspi->wcount > 0) {
+                       errors = davinci_spi_process_events(dspi);
+                       if (errors)
+                               break;
+                       cpu_relax();
+               }
+       }
 
-       if ((t->rx_buf) || (t->tx_buf))
-               davinci_spi_set_dma_req(spi, 1);
+       clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
+       if (spicfg->io_type == SPI_IO_TYPE_DMA) {
 
-       if (t->tx_buf)
-               wait_for_completion_interruptible(
-                               &davinci_spi_dma->dma_tx_completion);
+               if (t->tx_buf)
+                       dma_unmap_single(NULL, t->tx_dma, dspi->wcount,
+                                                               DMA_TO_DEVICE);
 
-       if (t->rx_buf)
-               wait_for_completion_interruptible(
-                               &davinci_spi_dma->dma_rx_completion);
+               dma_unmap_single(NULL, t->rx_dma, rx_buf_count,
+                                                       DMA_FROM_DEVICE);
 
-       dma_unmap_single(NULL, t->tx_dma, temp_count, DMA_TO_DEVICE);
+               clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
+       }
 
-       if (t->rx_buf)
-               dma_unmap_single(NULL, t->rx_dma, count, DMA_FROM_DEVICE);
+       clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
+       set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
 
        /*
         * Check for bit error, desync error,parity error,timeout error and
         * receive overflow errors
         */
-       int_status = ioread32(davinci_spi->base + SPIFLG);
-
-       ret = davinci_spi_check_error(davinci_spi, int_status);
-       if (ret != 0)
+       if (errors) {
+               ret = davinci_spi_check_error(dspi, errors);
+               WARN(!ret, "%s: error reported but no error found!\n",
+                                                       dev_name(&spi->dev));
                return ret;
+       }
 
-       /* SPI Framework maintains the count only in bytes so convert back */
-       davinci_spi->count *= conv;
+       if (dspi->rcount != 0 || dspi->wcount != 0) {
+               dev_err(sdev, "SPI data transfer error\n");
+               return -EIO;
+       }
 
        return t->len;
 }
 
 /**
- * davinci_spi_irq - IRQ handler for DaVinci SPI
+ * davinci_spi_irq - Interrupt handler for SPI Master Controller
  * @irq: IRQ number for this SPI Master
  * @context_data: structure for SPI Master controller davinci_spi
+ *
+ * ISR will determine that interrupt arrives either for READ or WRITE command.
+ * According to command it will do the appropriate action. It will check
+ * transfer length and if it is not zero then dispatch transfer command again.
+ * If transfer length is zero then it will indicate the COMPLETION so that
+ * davinci_spi_bufs function can go ahead.
  */
-static irqreturn_t davinci_spi_irq(s32 irq, void *context_data)
+static irqreturn_t davinci_spi_irq(s32 irq, void *data)
 {
-       struct davinci_spi *davinci_spi = context_data;
-       u32 int_status, rx_data = 0;
-       irqreturn_t ret = IRQ_NONE;
+       struct davinci_spi *dspi = data;
+       int status;
 
-       int_status = ioread32(davinci_spi->base + SPIFLG);
+       status = davinci_spi_process_events(dspi);
+       if (unlikely(status != 0))
+               clear_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
 
-       while ((int_status & SPIFLG_RX_INTR_MASK)) {
-               if (likely(int_status & SPIFLG_RX_INTR_MASK)) {
-                       ret = IRQ_HANDLED;
+       if ((!dspi->rcount && !dspi->wcount) || status)
+               complete(&dspi->done);
 
-                       rx_data = ioread32(davinci_spi->base + SPIBUF);
-                       davinci_spi->get_rx(rx_data, davinci_spi);
+       return IRQ_HANDLED;
+}
 
-                       /* Disable Receive Interrupt */
-                       iowrite32(~(SPIINT_RX_INTR | SPIINT_TX_INTR),
-                                       davinci_spi->base + SPIINT);
-               } else
-                       (void)davinci_spi_check_error(davinci_spi, int_status);
+static int davinci_spi_request_dma(struct davinci_spi *dspi)
+{
+       int r;
+       struct davinci_spi_dma *dma = &dspi->dma;
 
-               int_status = ioread32(davinci_spi->base + SPIFLG);
+       r = edma_alloc_channel(dma->rx_channel, davinci_spi_dma_callback, dspi,
+                                                               dma->eventq);
+       if (r < 0) {
+               pr_err("Unable to request DMA channel for SPI RX\n");
+               r = -EAGAIN;
+               goto rx_dma_failed;
        }
 
-       return ret;
+       r = edma_alloc_channel(dma->tx_channel, davinci_spi_dma_callback, dspi,
+                                                               dma->eventq);
+       if (r < 0) {
+               pr_err("Unable to request DMA channel for SPI TX\n");
+               r = -EAGAIN;
+               goto tx_dma_failed;
+       }
+
+       r = edma_alloc_slot(EDMA_CTLR(dma->tx_channel), EDMA_SLOT_ANY);
+       if (r < 0) {
+               pr_err("Unable to request SPI TX DMA param slot\n");
+               r = -EAGAIN;
+               goto param_failed;
+       }
+       dma->dummy_param_slot = r;
+       edma_link(dma->dummy_param_slot, dma->dummy_param_slot);
+
+       return 0;
+param_failed:
+       edma_free_channel(dma->tx_channel);
+tx_dma_failed:
+       edma_free_channel(dma->rx_channel);
+rx_dma_failed:
+       return r;
 }
 
 /**
  * davinci_spi_probe - probe function for SPI Master Controller
  * @pdev: platform_device structure which contains plateform specific data
+ *
+ * According to Linux Device Model this function will be invoked by Linux
+ * with platform_device struct which contains the device specific info.
+ * This function will map the SPI controller's memory, register IRQ,
+ * Reset SPI controller and setting its registers to default value.
+ * It will invoke spi_bitbang_start to create work queue so that client driver
+ * can register transfer method to work queue.
  */
 static int davinci_spi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
-       struct davinci_spi *davinci_spi;
+       struct davinci_spi *dspi;
        struct davinci_spi_platform_data *pdata;
        struct resource *r, *mem;
        resource_size_t dma_rx_chan = SPI_NO_RESOURCE;
        resource_size_t dma_tx_chan = SPI_NO_RESOURCE;
        resource_size_t dma_eventq = SPI_NO_RESOURCE;
        int i = 0, ret = 0;
+       u32 spipc0;
 
        pdata = pdev->dev.platform_data;
        if (pdata == NULL) {
@@ -1035,8 +808,8 @@ static int davinci_spi_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, master);
 
-       davinci_spi = spi_master_get_devdata(master);
-       if (davinci_spi == NULL) {
+       dspi = spi_master_get_devdata(master);
+       if (dspi == NULL) {
                ret = -ENOENT;
                goto free_master;
        }
@@ -1047,164 +820,143 @@ static int davinci_spi_probe(struct platform_device *pdev)
                goto free_master;
        }
 
-       davinci_spi->pbase = r->start;
-       davinci_spi->region_size = resource_size(r);
-       davinci_spi->pdata = pdata;
+       dspi->pbase = r->start;
+       dspi->pdata = pdata;
 
-       mem = request_mem_region(r->start, davinci_spi->region_size,
-                                       pdev->name);
+       mem = request_mem_region(r->start, resource_size(r), pdev->name);
        if (mem == NULL) {
                ret = -EBUSY;
                goto free_master;
        }
 
-       davinci_spi->base = (struct davinci_spi_reg __iomem *)
-                       ioremap(r->start, davinci_spi->region_size);
-       if (davinci_spi->base == NULL) {
+       dspi->base = ioremap(r->start, resource_size(r));
+       if (dspi->base == NULL) {
                ret = -ENOMEM;
                goto release_region;
        }
 
-       davinci_spi->irq = platform_get_irq(pdev, 0);
-       if (davinci_spi->irq <= 0) {
+       dspi->irq = platform_get_irq(pdev, 0);
+       if (dspi->irq <= 0) {
                ret = -EINVAL;
                goto unmap_io;
        }
 
-       ret = request_irq(davinci_spi->irq, davinci_spi_irq, IRQF_DISABLED,
-                         dev_name(&pdev->dev), davinci_spi);
+       ret = request_irq(dspi->irq, davinci_spi_irq, 0, dev_name(&pdev->dev),
+                                                                       dspi);
        if (ret)
                goto unmap_io;
 
-       /* Allocate tmp_buf for tx_buf */
-       davinci_spi->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL);
-       if (davinci_spi->tmp_buf == NULL) {
-               ret = -ENOMEM;
-               goto irq_free;
-       }
-
-       davinci_spi->bitbang.master = spi_master_get(master);
-       if (davinci_spi->bitbang.master == NULL) {
+       dspi->bitbang.master = spi_master_get(master);
+       if (dspi->bitbang.master == NULL) {
                ret = -ENODEV;
-               goto free_tmp_buf;
+               goto irq_free;
        }
 
-       davinci_spi->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(davinci_spi->clk)) {
+       dspi->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(dspi->clk)) {
                ret = -ENODEV;
                goto put_master;
        }
-       clk_enable(davinci_spi->clk);
-
+       clk_enable(dspi->clk);
 
        master->bus_num = pdev->id;
        master->num_chipselect = pdata->num_chipselect;
        master->setup = davinci_spi_setup;
-       master->cleanup = davinci_spi_cleanup;
-
-       davinci_spi->bitbang.chipselect = davinci_spi_chipselect;
-       davinci_spi->bitbang.setup_transfer = davinci_spi_setup_transfer;
-
-       davinci_spi->version = pdata->version;
-       use_dma = pdata->use_dma;
-
-       davinci_spi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
-       if (davinci_spi->version == SPI_VERSION_2)
-               davinci_spi->bitbang.flags |= SPI_READY;
-
-       if (use_dma) {
-                       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-                       if (r)
-                               dma_rx_chan = r->start;
-                       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-                       if (r)
-                               dma_tx_chan = r->start;
-                       r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
-                       if (r)
-                               dma_eventq = r->start;
-       }
 
-       if (!use_dma ||
-           dma_rx_chan == SPI_NO_RESOURCE ||
-           dma_tx_chan == SPI_NO_RESOURCE ||
-           dma_eventq  == SPI_NO_RESOURCE) {
-               davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio;
-               use_dma = 0;
-       } else {
-               davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma;
-               davinci_spi->dma_channels = kzalloc(master->num_chipselect
-                               * sizeof(struct davinci_spi_dma), GFP_KERNEL);
-               if (davinci_spi->dma_channels == NULL) {
-                       ret = -ENOMEM;
+       dspi->bitbang.chipselect = davinci_spi_chipselect;
+       dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
+
+       dspi->version = pdata->version;
+
+       dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
+       if (dspi->version == SPI_VERSION_2)
+               dspi->bitbang.flags |= SPI_READY;
+
+       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (r)
+               dma_rx_chan = r->start;
+       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (r)
+               dma_tx_chan = r->start;
+       r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+       if (r)
+               dma_eventq = r->start;
+
+       dspi->bitbang.txrx_bufs = davinci_spi_bufs;
+       if (dma_rx_chan != SPI_NO_RESOURCE &&
+           dma_tx_chan != SPI_NO_RESOURCE &&
+           dma_eventq != SPI_NO_RESOURCE) {
+               dspi->dma.rx_channel = dma_rx_chan;
+               dspi->dma.tx_channel = dma_tx_chan;
+               dspi->dma.eventq = dma_eventq;
+
+               ret = davinci_spi_request_dma(dspi);
+               if (ret)
                        goto free_clk;
-               }
 
-               for (i = 0; i < master->num_chipselect; i++) {
-                       davinci_spi->dma_channels[i].dma_rx_channel = -1;
-                       davinci_spi->dma_channels[i].dma_rx_sync_dev =
-                               dma_rx_chan;
-                       davinci_spi->dma_channels[i].dma_tx_channel = -1;
-                       davinci_spi->dma_channels[i].dma_tx_sync_dev =
-                               dma_tx_chan;
-                       davinci_spi->dma_channels[i].eventq = dma_eventq;
-               }
-               dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n"
-                               "Using RX channel = %d , TX channel = %d and "
-                               "event queue = %d", dma_rx_chan, dma_tx_chan,
+               dev_info(&pdev->dev, "DMA: supported\n");
+               dev_info(&pdev->dev, "DMA: RX channel: %d, TX channel: %d, "
+                               "event queue: %d\n", dma_rx_chan, dma_tx_chan,
                                dma_eventq);
        }
 
-       davinci_spi->get_rx = davinci_spi_rx_buf_u8;
-       davinci_spi->get_tx = davinci_spi_tx_buf_u8;
+       dspi->get_rx = davinci_spi_rx_buf_u8;
+       dspi->get_tx = davinci_spi_tx_buf_u8;
 
-       init_completion(&davinci_spi->done);
+       init_completion(&dspi->done);
 
        /* Reset In/OUT SPI module */
-       iowrite32(0, davinci_spi->base + SPIGCR0);
+       iowrite32(0, dspi->base + SPIGCR0);
        udelay(100);
-       iowrite32(1, davinci_spi->base + SPIGCR0);
+       iowrite32(1, dspi->base + SPIGCR0);
 
-       /* Clock internal */
-       if (davinci_spi->pdata->clk_internal)
-               set_io_bits(davinci_spi->base + SPIGCR1,
-                               SPIGCR1_CLKMOD_MASK);
-       else
-               clear_io_bits(davinci_spi->base + SPIGCR1,
-                               SPIGCR1_CLKMOD_MASK);
+       /* Set up SPIPC0.  CS and ENA init is done in davinci_spi_setup */
+       spipc0 = SPIPC0_DIFUN_MASK | SPIPC0_DOFUN_MASK | SPIPC0_CLKFUN_MASK;
+       iowrite32(spipc0, dspi->base + SPIPC0);
 
-       /* master mode default */
-       set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
+       /* initialize chip selects */
+       if (pdata->chip_sel) {
+               for (i = 0; i < pdata->num_chipselect; i++) {
+                       if (pdata->chip_sel[i] != SPI_INTERN_CS)
+                               gpio_direction_output(pdata->chip_sel[i], 1);
+               }
+       }
 
-       if (davinci_spi->pdata->intr_level)
-               iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL);
+       if (pdata->intr_line)
+               iowrite32(SPI_INTLVL_1, dspi->base + SPILVL);
        else
-               iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL);
+               iowrite32(SPI_INTLVL_0, dspi->base + SPILVL);
 
-       ret = spi_bitbang_start(&davinci_spi->bitbang);
-       if (ret)
-               goto free_clk;
+       iowrite32(CS_DEFAULT, dspi->base + SPIDEF);
 
-       dev_info(&pdev->dev, "Controller at 0x%p \n", davinci_spi->base);
+       /* master mode default */
+       set_io_bits(dspi->base + SPIGCR1, SPIGCR1_CLKMOD_MASK);
+       set_io_bits(dspi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
+       set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
+
+       ret = spi_bitbang_start(&dspi->bitbang);
+       if (ret)
+               goto free_dma;
 
-       if (!pdata->poll_mode)
-               dev_info(&pdev->dev, "Operating in interrupt mode"
-                       " using IRQ %d\n", davinci_spi->irq);
+       dev_info(&pdev->dev, "Controller at 0x%p\n", dspi->base);
 
        return ret;
 
+free_dma:
+       edma_free_channel(dspi->dma.tx_channel);
+       edma_free_channel(dspi->dma.rx_channel);
+       edma_free_slot(dspi->dma.dummy_param_slot);
 free_clk:
-       clk_disable(davinci_spi->clk);
-       clk_put(davinci_spi->clk);
+       clk_disable(dspi->clk);
+       clk_put(dspi->clk);
 put_master:
        spi_master_put(master);
-free_tmp_buf:
-       kfree(davinci_spi->tmp_buf);
 irq_free:
-       free_irq(davinci_spi->irq, davinci_spi);
+       free_irq(dspi->irq, dspi);
 unmap_io:
-       iounmap(davinci_spi->base);
+       iounmap(dspi->base);
 release_region:
-       release_mem_region(davinci_spi->pbase, davinci_spi->region_size);
+       release_mem_region(dspi->pbase, resource_size(r));
 free_master:
        kfree(master);
 err:
@@ -1222,27 +974,31 @@ err:
  */
 static int __exit davinci_spi_remove(struct platform_device *pdev)
 {
-       struct davinci_spi *davinci_spi;
+       struct davinci_spi *dspi;
        struct spi_master *master;
+       struct resource *r;
 
        master = dev_get_drvdata(&pdev->dev);
-       davinci_spi = spi_master_get_devdata(master);
+       dspi = spi_master_get_devdata(master);
 
-       spi_bitbang_stop(&davinci_spi->bitbang);
+       spi_bitbang_stop(&dspi->bitbang);
 
-       clk_disable(davinci_spi->clk);
-       clk_put(davinci_spi->clk);
+       clk_disable(dspi->clk);
+       clk_put(dspi->clk);
        spi_master_put(master);
-       kfree(davinci_spi->tmp_buf);
-       free_irq(davinci_spi->irq, davinci_spi);
-       iounmap(davinci_spi->base);
-       release_mem_region(davinci_spi->pbase, davinci_spi->region_size);
+       free_irq(dspi->irq, dspi);
+       iounmap(dspi->base);
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(dspi->pbase, resource_size(r));
 
        return 0;
 }
 
 static struct platform_driver davinci_spi_driver = {
-       .driver.name = "spi_davinci",
+       .driver = {
+               .name = "spi_davinci",
+               .owner = THIS_MODULE,
+       },
        .remove = __exit_p(davinci_spi_remove),
 };
 
index 0838c79861e49f9a0c97189af9ab25d3c0269b76..22af77f98816c5116a1e138f59dc169d0e52ff71 100644 (file)
@@ -164,20 +164,23 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
 
 static void wait_till_not_busy(struct dw_spi *dws)
 {
-       unsigned long end = jiffies + 1 + usecs_to_jiffies(1000);
+       unsigned long end = jiffies + 1 + usecs_to_jiffies(5000);
 
        while (time_before(jiffies, end)) {
                if (!(dw_readw(dws, sr) & SR_BUSY))
                        return;
+               cpu_relax();
        }
        dev_err(&dws->master->dev,
-               "DW SPI: Status keeps busy for 1000us after a read/write!\n");
+               "DW SPI: Status keeps busy for 5000us after a read/write!\n");
 }
 
 static void flush(struct dw_spi *dws)
 {
-       while (dw_readw(dws, sr) & SR_RF_NOT_EMPT)
+       while (dw_readw(dws, sr) & SR_RF_NOT_EMPT) {
                dw_readw(dws, dr);
+               cpu_relax();
+       }
 
        wait_till_not_busy(dws);
 }
@@ -285,8 +288,10 @@ static void *next_transfer(struct dw_spi *dws)
  */
 static int map_dma_buffers(struct dw_spi *dws)
 {
-       if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited
-               || !dws->cur_chip->enable_dma)
+       if (!dws->cur_msg->is_dma_mapped
+               || !dws->dma_inited
+               || !dws->cur_chip->enable_dma
+               || !dws->dma_ops)
                return 0;
 
        if (dws->cur_transfer->tx_dma)
@@ -338,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg)
        tasklet_schedule(&dws->pump_transfers);
 }
 
-static void transfer_complete(struct dw_spi *dws)
+void dw_spi_xfer_done(struct dw_spi *dws)
 {
        /* Update total byte transfered return count actual bytes read */
        dws->cur_msg->actual_length += dws->len;
@@ -353,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws)
        } else
                tasklet_schedule(&dws->pump_transfers);
 }
+EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
 
 static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 {
@@ -384,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
                if (dws->tx_end > dws->tx)
                        spi_umask_intr(dws, SPI_INT_TXEI);
                else
-                       transfer_complete(dws);
+                       dw_spi_xfer_done(dws);
        }
 
        return IRQ_HANDLED;
@@ -419,11 +425,7 @@ static void poll_transfer(struct dw_spi *dws)
         */
        dws->read(dws);
 
-       transfer_complete(dws);
-}
-
-static void dma_transfer(struct dw_spi *dws, int cs_change)
-{
+       dw_spi_xfer_done(dws);
 }
 
 static void pump_transfers(unsigned long data)
@@ -592,7 +594,7 @@ static void pump_transfers(unsigned long data)
                spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
                spi_chip_sel(dws, spi->chip_select);
 
-               /* Set the interrupt mask, for poll mode just diable all int */
+               /* Set the interrupt mask, for poll mode just disable all int */
                spi_mask_intr(dws, 0xff);
                if (imask)
                        spi_umask_intr(dws, imask);
@@ -605,7 +607,7 @@ static void pump_transfers(unsigned long data)
        }
 
        if (dws->dma_mapped)
-               dma_transfer(dws, cs_change);
+               dws->dma_ops->dma_transfer(dws, cs_change);
 
        if (chip->poll_mode)
                poll_transfer(dws);
@@ -901,11 +903,17 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
        master->setup = dw_spi_setup;
        master->transfer = dw_spi_transfer;
 
-       dws->dma_inited = 0;
-
        /* Basic HW init */
        spi_hw_init(dws);
 
+       if (dws->dma_ops && dws->dma_ops->dma_init) {
+               ret = dws->dma_ops->dma_init(dws);
+               if (ret) {
+                       dev_warn(&master->dev, "DMA init failed\n");
+                       dws->dma_inited = 0;
+               }
+       }
+
        /* Initial and start queue */
        ret = init_queue(dws);
        if (ret) {
@@ -930,6 +938,8 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
 
 err_queue_alloc:
        destroy_queue(dws);
+       if (dws->dma_ops && dws->dma_ops->dma_exit)
+               dws->dma_ops->dma_exit(dws);
 err_diable_hw:
        spi_enable_chip(dws, 0);
        free_irq(dws->irq, dws);
@@ -938,7 +948,7 @@ err_free_master:
 exit:
        return ret;
 }
-EXPORT_SYMBOL(dw_spi_add_host);
+EXPORT_SYMBOL_GPL(dw_spi_add_host);
 
 void __devexit dw_spi_remove_host(struct dw_spi *dws)
 {
@@ -954,6 +964,8 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
                dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not "
                        "complete, message memory not freed\n");
 
+       if (dws->dma_ops && dws->dma_ops->dma_exit)
+               dws->dma_ops->dma_exit(dws);
        spi_enable_chip(dws, 0);
        /* Disable clk */
        spi_set_clk(dws, 0);
@@ -962,7 +974,7 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
        /* Disconnect from the SPI framework */
        spi_unregister_master(dws->master);
 }
-EXPORT_SYMBOL(dw_spi_remove_host);
+EXPORT_SYMBOL_GPL(dw_spi_remove_host);
 
 int dw_spi_suspend_host(struct dw_spi *dws)
 {
@@ -975,7 +987,7 @@ int dw_spi_suspend_host(struct dw_spi *dws)
        spi_set_clk(dws, 0);
        return ret;
 }
-EXPORT_SYMBOL(dw_spi_suspend_host);
+EXPORT_SYMBOL_GPL(dw_spi_suspend_host);
 
 int dw_spi_resume_host(struct dw_spi *dws)
 {
@@ -987,7 +999,7 @@ int dw_spi_resume_host(struct dw_spi *dws)
                dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
        return ret;
 }
-EXPORT_SYMBOL(dw_spi_resume_host);
+EXPORT_SYMBOL_GPL(dw_spi_resume_host);
 
 MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
 MODULE_DESCRIPTION("Driver for DesignWare SPI controller core");
diff --git a/drivers/spi/dw_spi_mid.c b/drivers/spi/dw_spi_mid.c
new file mode 100644 (file)
index 0000000..c91c966
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * dw_spi_mid.c - special handling for DW core on Intel MID platform
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/dw_spi.h>
+
+#ifdef CONFIG_SPI_DW_MID_DMA
+#include <linux/intel_mid_dma.h>
+#include <linux/pci.h>
+
+struct mid_dma {
+       struct intel_mid_dma_slave      dmas_tx;
+       struct intel_mid_dma_slave      dmas_rx;
+};
+
+static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
+{
+       struct dw_spi *dws = param;
+
+       return dws->dmac && (&dws->dmac->dev == chan->device->dev);
+}
+
+static int mid_spi_dma_init(struct dw_spi *dws)
+{
+       struct mid_dma *dw_dma = dws->dma_priv;
+       struct intel_mid_dma_slave *rxs, *txs;
+       dma_cap_mask_t mask;
+
+       /*
+        * Get pci device for DMA controller, currently it could only
+        * be the DMA controller of either Moorestown or Medfield
+        */
+       dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0813, NULL);
+       if (!dws->dmac)
+               dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL);
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       /* 1. Init rx channel */
+       dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
+       if (!dws->rxchan)
+               goto err_exit;
+       rxs = &dw_dma->dmas_rx;
+       rxs->hs_mode = LNW_DMA_HW_HS;
+       rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
+       dws->rxchan->private = rxs;
+
+       /* 2. Init tx channel */
+       dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
+       if (!dws->txchan)
+               goto free_rxchan;
+       txs = &dw_dma->dmas_tx;
+       txs->hs_mode = LNW_DMA_HW_HS;
+       txs->cfg_mode = LNW_DMA_MEM_TO_PER;
+       dws->txchan->private = txs;
+
+       dws->dma_inited = 1;
+       return 0;
+
+free_rxchan:
+       dma_release_channel(dws->rxchan);
+err_exit:
+       return -1;
+
+}
+
+static void mid_spi_dma_exit(struct dw_spi *dws)
+{
+       dma_release_channel(dws->txchan);
+       dma_release_channel(dws->rxchan);
+}
+
+/*
+ * dws->dma_chan_done is cleared before the dma transfer starts,
+ * callback for rx/tx channel will each increment it by 1.
+ * Reaching 2 means the whole spi transaction is done.
+ */
+static void dw_spi_dma_done(void *arg)
+{
+       struct dw_spi *dws = arg;
+
+       if (++dws->dma_chan_done != 2)
+               return;
+       dw_spi_xfer_done(dws);
+}
+
+static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
+{
+       struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
+       struct dma_chan *txchan, *rxchan;
+       struct dma_slave_config txconf, rxconf;
+       u16 dma_ctrl = 0;
+
+       /* 1. setup DMA related registers */
+       if (cs_change) {
+               spi_enable_chip(dws, 0);
+               dw_writew(dws, dmardlr, 0xf);
+               dw_writew(dws, dmatdlr, 0x10);
+               if (dws->tx_dma)
+                       dma_ctrl |= 0x2;
+               if (dws->rx_dma)
+                       dma_ctrl |= 0x1;
+               dw_writew(dws, dmacr, dma_ctrl);
+               spi_enable_chip(dws, 1);
+       }
+
+       dws->dma_chan_done = 0;
+       txchan = dws->txchan;
+       rxchan = dws->rxchan;
+
+       /* 2. Prepare the TX dma transfer */
+       txconf.direction = DMA_TO_DEVICE;
+       txconf.dst_addr = dws->dma_addr;
+       txconf.dst_maxburst = LNW_DMA_MSIZE_16;
+       txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+       txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
+                                      (unsigned long) &txconf);
+
+       memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
+       dws->tx_sgl.dma_address = dws->tx_dma;
+       dws->tx_sgl.length = dws->len;
+
+       txdesc = txchan->device->device_prep_slave_sg(txchan,
+                               &dws->tx_sgl,
+                               1,
+                               DMA_TO_DEVICE,
+                               DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
+       txdesc->callback = dw_spi_dma_done;
+       txdesc->callback_param = dws;
+
+       /* 3. Prepare the RX dma transfer */
+       rxconf.direction = DMA_FROM_DEVICE;
+       rxconf.src_addr = dws->dma_addr;
+       rxconf.src_maxburst = LNW_DMA_MSIZE_16;
+       rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+       rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
+                                      (unsigned long) &rxconf);
+
+       memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
+       dws->rx_sgl.dma_address = dws->rx_dma;
+       dws->rx_sgl.length = dws->len;
+
+       rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+                               &dws->rx_sgl,
+                               1,
+                               DMA_FROM_DEVICE,
+                               DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
+       rxdesc->callback = dw_spi_dma_done;
+       rxdesc->callback_param = dws;
+
+       /* rx must be started before tx due to spi instinct */
+       rxdesc->tx_submit(rxdesc);
+       txdesc->tx_submit(txdesc);
+       return 0;
+}
+
+static struct dw_spi_dma_ops mid_dma_ops = {
+       .dma_init       = mid_spi_dma_init,
+       .dma_exit       = mid_spi_dma_exit,
+       .dma_transfer   = mid_spi_dma_transfer,
+};
+#endif
+
+/* Some specific info for SPI0 controller on Moorestown */
+
+/* HW info for MRST CLk Control Unit, one 32b reg */
+#define MRST_SPI_CLK_BASE      100000000       /* 100m */
+#define MRST_CLK_SPI0_REG      0xff11d86c
+#define CLK_SPI_BDIV_OFFSET    0
+#define CLK_SPI_BDIV_MASK      0x00000007
+#define CLK_SPI_CDIV_OFFSET    9
+#define CLK_SPI_CDIV_MASK      0x00000e00
+#define CLK_SPI_DISABLE_OFFSET 8
+
+int dw_spi_mid_init(struct dw_spi *dws)
+{
+       u32 *clk_reg, clk_cdiv;
+
+       clk_reg = ioremap_nocache(MRST_CLK_SPI0_REG, 16);
+       if (!clk_reg)
+               return -ENOMEM;
+
+       /* get SPI controller operating freq info */
+       clk_cdiv  = (readl(clk_reg) & CLK_SPI_CDIV_MASK) >> CLK_SPI_CDIV_OFFSET;
+       dws->max_freq = MRST_SPI_CLK_BASE / (clk_cdiv + 1);
+       iounmap(clk_reg);
+
+       dws->num_cs = 16;
+       dws->fifo_len = 40;     /* FIFO has 40 words buffer */
+
+#ifdef CONFIG_SPI_DW_MID_DMA
+       dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL);
+       if (!dws->dma_priv)
+               return -ENOMEM;
+       dws->dma_ops = &mid_dma_ops;
+#endif
+       return 0;
+}
index 1f52755dc87824e9764b354557c86dfd901dc4a3..49ec3aa1219f51d79f6218f54a96960c471cf809 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * mrst_spi_pci.c - PCI interface driver for DW SPI Core
+ * dw_spi_pci.c - PCI interface driver for DW SPI Core
  *
  * Copyright (c) 2009, Intel Corporation.
  *
@@ -26,8 +26,8 @@
 #define DRIVER_NAME "dw_spi_pci"
 
 struct dw_spi_pci {
-       struct pci_dev          *pdev;
-       struct dw_spi           dws;
+       struct pci_dev  *pdev;
+       struct dw_spi   dws;
 };
 
 static int __devinit spi_pci_probe(struct pci_dev *pdev,
@@ -72,9 +72,17 @@ static int __devinit spi_pci_probe(struct pci_dev *pdev,
        dws->parent_dev = &pdev->dev;
        dws->bus_num = 0;
        dws->num_cs = 4;
-       dws->max_freq = 25000000;       /* for Moorestwon */
        dws->irq = pdev->irq;
-       dws->fifo_len = 40;             /* FIFO has 40 words buffer */
+
+       /*
+        * Specific handling for Intel MID paltforms, like dma setup,
+        * clock rate, FIFO depth.
+        */
+       if (pdev->device == 0x0800) {
+               ret = dw_spi_mid_init(dws);
+               if (ret)
+                       goto err_unmap;
+       }
 
        ret = dw_spi_add_host(dws);
        if (ret)
@@ -140,7 +148,7 @@ static int spi_resume(struct pci_dev *pdev)
 #endif
 
 static const struct pci_device_id pci_ids[] __devinitdata = {
-       /* Intel Moorestown platform SPI controller 0 */
+       /* Intel MID platform SPI controller 0 */
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) },
        {},
 };
index 983fbbfce76eba3061e073ab5c03aa48d9dd89c3..8a904c1c8485e67f215971932782c2f02a29eff5 100644 (file)
@@ -363,7 +363,7 @@ static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
 }
 
 /* bus_num is used only for the case dev->platform_data == NULL */
-static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
+static int __devinit mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
                                u32 size, unsigned int irq, s16 bus_num)
 {
        struct fsl_spi_platform_data *pdata = dev->platform_data;
@@ -450,22 +450,7 @@ free_master:
        return ret;
 }
 
-static int __exit mpc52xx_psc_spi_do_remove(struct device *dev)
-{
-       struct spi_master *master = dev_get_drvdata(dev);
-       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
-
-       flush_workqueue(mps->workqueue);
-       destroy_workqueue(mps->workqueue);
-       spi_unregister_master(master);
-       free_irq(mps->irq, mps);
-       if (mps->psc)
-               iounmap(mps->psc);
-
-       return 0;
-}
-
-static int __init mpc52xx_psc_spi_of_probe(struct platform_device *op,
+static int __devinit mpc52xx_psc_spi_of_probe(struct platform_device *op,
        const struct of_device_id *match)
 {
        const u32 *regaddr_p;
@@ -495,9 +480,19 @@ static int __init mpc52xx_psc_spi_of_probe(struct platform_device *op,
                                irq_of_parse_and_map(op->dev.of_node, 0), id);
 }
 
-static int __exit mpc52xx_psc_spi_of_remove(struct platform_device *op)
+static int __devexit mpc52xx_psc_spi_of_remove(struct platform_device *op)
 {
-       return mpc52xx_psc_spi_do_remove(&op->dev);
+       struct spi_master *master = dev_get_drvdata(&op->dev);
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
+
+       flush_workqueue(mps->workqueue);
+       destroy_workqueue(mps->workqueue);
+       spi_unregister_master(master);
+       free_irq(mps->irq, mps);
+       if (mps->psc)
+               iounmap(mps->psc);
+
+       return 0;
 }
 
 static const struct of_device_id mpc52xx_psc_spi_of_match[] = {
@@ -510,7 +505,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
 
 static struct of_platform_driver mpc52xx_psc_spi_of_driver = {
        .probe = mpc52xx_psc_spi_of_probe,
-       .remove = __exit_p(mpc52xx_psc_spi_of_remove),
+       .remove = __devexit_p(mpc52xx_psc_spi_of_remove),
        .driver = {
                .name = "mpc52xx-psc-spi",
                .owner = THIS_MODULE,
index 951a160fc27fbe2614376776ba3b712646e305ff..abb1ffbf3d2019154855c29028418c0f3e85beae 100644 (file)
@@ -397,7 +397,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 
        if (tx != NULL) {
                wait_for_completion(&mcspi_dma->dma_tx_completion);
-               dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE);
+               dma_unmap_single(&spi->dev, xfer->tx_dma, count, DMA_TO_DEVICE);
 
                /* for TX_ONLY mode, be sure all words have shifted out */
                if (rx == NULL) {
@@ -412,7 +412,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 
        if (rx != NULL) {
                wait_for_completion(&mcspi_dma->dma_rx_completion);
-               dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
+               dma_unmap_single(&spi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE);
                omap2_mcspi_set_enable(spi, 0);
 
                if (l & OMAP2_MCSPI_CHCONF_TURBO) {
@@ -1025,11 +1025,6 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
                if (m->is_dma_mapped || len < DMA_MIN_BYTES)
                        continue;
 
-               /* Do DMA mapping "early" for better error reporting and
-                * dcache use.  Note that if dma_unmap_single() ever starts
-                * to do real work on ARM, we'd need to clean up mappings
-                * for previous transfers on *ALL* exits of this loop...
-                */
                if (tx_buf != NULL) {
                        t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf,
                                        len, DMA_TO_DEVICE);
@@ -1046,7 +1041,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
                                dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
                                                'R', len);
                                if (tx_buf != NULL)
-                                       dma_unmap_single(NULL, t->tx_dma,
+                                       dma_unmap_single(&spi->dev, t->tx_dma,
                                                        len, DMA_TO_DEVICE);
                                return -EINVAL;
                        }
index e76b1afafe07770beed07ac63881f5fa0a3c0b2d..95928833855b0e922bf5ee23ea6ff36241e8b2bb 100644 (file)
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/dma-mapping.h>
 #include <linux/spi/spi.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
-#include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
 
@@ -35,9 +35,6 @@
 #include <asm/irq.h>
 #include <asm/delay.h>
 
-#include <mach/dma.h>
-#include <plat/ssp.h>
-#include <mach/pxa2xx_spi.h>
 
 MODULE_AUTHOR("Stephen Street");
 MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
@@ -46,8 +43,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
 
 #define MAX_BUSES 3
 
-#define RX_THRESH_DFLT         8
-#define TX_THRESH_DFLT         8
 #define TIMOUT_DFLT            1000
 
 #define DMA_INT_MASK           (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
@@ -168,7 +163,10 @@ struct chip_data {
        u8 enable_dma;
        u8 bits_per_word;
        u32 speed_hz;
-       int gpio_cs;
+       union {
+               int gpio_cs;
+               unsigned int frm;
+       };
        int gpio_cs_inverted;
        int (*write)(struct driver_data *drv_data);
        int (*read)(struct driver_data *drv_data);
@@ -181,6 +179,11 @@ static void cs_assert(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
+       if (drv_data->ssp_type == CE4100_SSP) {
+               write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr);
+               return;
+       }
+
        if (chip->cs_control) {
                chip->cs_control(PXA2XX_CS_ASSERT);
                return;
@@ -194,6 +197,9 @@ static void cs_deassert(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
+       if (drv_data->ssp_type == CE4100_SSP)
+               return;
+
        if (chip->cs_control) {
                chip->cs_control(PXA2XX_CS_DEASSERT);
                return;
@@ -203,6 +209,25 @@ static void cs_deassert(struct driver_data *drv_data)
                gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
 }
 
+static void write_SSSR_CS(struct driver_data *drv_data, u32 val)
+{
+       void __iomem *reg = drv_data->ioaddr;
+
+       if (drv_data->ssp_type == CE4100_SSP)
+               val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
+
+       write_SSSR(val, reg);
+}
+
+static int pxa25x_ssp_comp(struct driver_data *drv_data)
+{
+       if (drv_data->ssp_type == PXA25x_SSP)
+               return 1;
+       if (drv_data->ssp_type == CE4100_SSP)
+               return 1;
+       return 0;
+}
+
 static int flush(struct driver_data *drv_data)
 {
        unsigned long limit = loops_per_jiffy << 1;
@@ -214,7 +239,7 @@ static int flush(struct driver_data *drv_data)
                        read_SSDR(reg);
                }
        } while ((read_SSSR(reg) & SSSR_BSY) && --limit);
-       write_SSSR(SSSR_ROR, reg);
+       write_SSSR_CS(drv_data, SSSR_ROR);
 
        return limit;
 }
@@ -224,7 +249,7 @@ static int null_writer(struct driver_data *drv_data)
        void __iomem *reg = drv_data->ioaddr;
        u8 n_bytes = drv_data->n_bytes;
 
-       if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+       if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
                || (drv_data->tx == drv_data->tx_end))
                return 0;
 
@@ -252,7 +277,7 @@ static int u8_writer(struct driver_data *drv_data)
 {
        void __iomem *reg = drv_data->ioaddr;
 
-       if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+       if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
                || (drv_data->tx == drv_data->tx_end))
                return 0;
 
@@ -279,7 +304,7 @@ static int u16_writer(struct driver_data *drv_data)
 {
        void __iomem *reg = drv_data->ioaddr;
 
-       if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+       if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
                || (drv_data->tx == drv_data->tx_end))
                return 0;
 
@@ -306,7 +331,7 @@ static int u32_writer(struct driver_data *drv_data)
 {
        void __iomem *reg = drv_data->ioaddr;
 
-       if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+       if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
                || (drv_data->tx == drv_data->tx_end))
                return 0;
 
@@ -507,9 +532,9 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg)
        /* Stop and reset */
        DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
        DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
-       write_SSSR(drv_data->clear_sr, reg);
+       write_SSSR_CS(drv_data, drv_data->clear_sr);
        write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
-       if (drv_data->ssp_type != PXA25x_SSP)
+       if (!pxa25x_ssp_comp(drv_data))
                write_SSTO(0, reg);
        flush(drv_data);
        write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
@@ -529,7 +554,7 @@ static void dma_transfer_complete(struct driver_data *drv_data)
 
        /* Clear and disable interrupts on SSP and DMA channels*/
        write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
-       write_SSSR(drv_data->clear_sr, reg);
+       write_SSSR_CS(drv_data, drv_data->clear_sr);
        DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
        DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
 
@@ -622,7 +647,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
 
                /* Clear and disable timeout interrupt, do the rest in
                 * dma_transfer_complete */
-               if (drv_data->ssp_type != PXA25x_SSP)
+               if (!pxa25x_ssp_comp(drv_data))
                        write_SSTO(0, reg);
 
                /* finish this transfer, start the next */
@@ -635,14 +660,26 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
        return IRQ_NONE;
 }
 
+static void reset_sccr1(struct driver_data *drv_data)
+{
+       void __iomem *reg = drv_data->ioaddr;
+       struct chip_data *chip = drv_data->cur_chip;
+       u32 sccr1_reg;
+
+       sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1;
+       sccr1_reg &= ~SSCR1_RFT;
+       sccr1_reg |= chip->threshold;
+       write_SSCR1(sccr1_reg, reg);
+}
+
 static void int_error_stop(struct driver_data *drv_data, const char* msg)
 {
        void __iomem *reg = drv_data->ioaddr;
 
        /* Stop and reset SSP */
-       write_SSSR(drv_data->clear_sr, reg);
-       write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
-       if (drv_data->ssp_type != PXA25x_SSP)
+       write_SSSR_CS(drv_data, drv_data->clear_sr);
+       reset_sccr1(drv_data);
+       if (!pxa25x_ssp_comp(drv_data))
                write_SSTO(0, reg);
        flush(drv_data);
        write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
@@ -658,9 +695,9 @@ static void int_transfer_complete(struct driver_data *drv_data)
        void __iomem *reg = drv_data->ioaddr;
 
        /* Stop SSP */
-       write_SSSR(drv_data->clear_sr, reg);
-       write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
-       if (drv_data->ssp_type != PXA25x_SSP)
+       write_SSSR_CS(drv_data, drv_data->clear_sr);
+       reset_sccr1(drv_data);
+       if (!pxa25x_ssp_comp(drv_data))
                write_SSTO(0, reg);
 
        /* Update total byte transfered return count actual bytes read */
@@ -714,24 +751,34 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
        }
 
        if (drv_data->tx == drv_data->tx_end) {
-               write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
-               /* PXA25x_SSP has no timeout, read trailing bytes */
-               if (drv_data->ssp_type == PXA25x_SSP) {
-                       if (!wait_ssp_rx_stall(reg))
-                       {
-                               int_error_stop(drv_data, "interrupt_transfer: "
-                                               "rx stall failed");
-                               return IRQ_HANDLED;
-                       }
-                       if (!drv_data->read(drv_data))
-                       {
-                               int_error_stop(drv_data,
-                                               "interrupt_transfer: "
-                                               "trailing byte read failed");
-                               return IRQ_HANDLED;
+               u32 bytes_left;
+               u32 sccr1_reg;
+
+               sccr1_reg = read_SSCR1(reg);
+               sccr1_reg &= ~SSCR1_TIE;
+
+               /*
+                * PXA25x_SSP has no timeout, set up rx threshould for the
+                * remaing RX bytes.
+                */
+               if (pxa25x_ssp_comp(drv_data)) {
+
+                       sccr1_reg &= ~SSCR1_RFT;
+
+                       bytes_left = drv_data->rx_end - drv_data->rx;
+                       switch (drv_data->n_bytes) {
+                       case 4:
+                               bytes_left >>= 1;
+                       case 2:
+                               bytes_left >>= 1;
                        }
-                       int_transfer_complete(drv_data);
+
+                       if (bytes_left > RX_THRESH_DFLT)
+                               bytes_left = RX_THRESH_DFLT;
+
+                       sccr1_reg |= SSCR1_RxTresh(bytes_left);
                }
+               write_SSCR1(sccr1_reg, reg);
        }
 
        /* We did something */
@@ -742,14 +789,26 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
 {
        struct driver_data *drv_data = dev_id;
        void __iomem *reg = drv_data->ioaddr;
+       u32 sccr1_reg = read_SSCR1(reg);
+       u32 mask = drv_data->mask_sr;
+       u32 status;
+
+       status = read_SSSR(reg);
+
+       /* Ignore possible writes if we don't need to write */
+       if (!(sccr1_reg & SSCR1_TIE))
+               mask &= ~SSSR_TFS;
+
+       if (!(status & mask))
+               return IRQ_NONE;
 
        if (!drv_data->cur_msg) {
 
                write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
                write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
-               if (drv_data->ssp_type != PXA25x_SSP)
+               if (!pxa25x_ssp_comp(drv_data))
                        write_SSTO(0, reg);
-               write_SSSR(drv_data->clear_sr, reg);
+               write_SSSR_CS(drv_data, drv_data->clear_sr);
 
                dev_err(&drv_data->pdev->dev, "bad message state "
                        "in interrupt handler\n");
@@ -862,7 +921,7 @@ static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
 {
        unsigned long ssp_clk = clk_get_rate(ssp->clk);
 
-       if (ssp->type == PXA25x_SSP)
+       if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
                return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
        else
                return ((ssp_clk / rate - 1) & 0xfff) << 8;
@@ -1088,7 +1147,7 @@ static void pump_transfers(unsigned long data)
 
                /* Clear status  */
                cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
-               write_SSSR(drv_data->clear_sr, reg);
+               write_SSSR_CS(drv_data, drv_data->clear_sr);
        }
 
        /* see if we need to reload the config registers */
@@ -1098,7 +1157,7 @@ static void pump_transfers(unsigned long data)
 
                /* stop the SSP, and update the other bits */
                write_SSCR0(cr0 & ~SSCR0_SSE, reg);
-               if (drv_data->ssp_type != PXA25x_SSP)
+               if (!pxa25x_ssp_comp(drv_data))
                        write_SSTO(chip->timeout, reg);
                /* first set CR1 without interrupt and service enables */
                write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
@@ -1106,7 +1165,7 @@ static void pump_transfers(unsigned long data)
                write_SSCR0(cr0, reg);
 
        } else {
-               if (drv_data->ssp_type != PXA25x_SSP)
+               if (!pxa25x_ssp_comp(drv_data))
                        write_SSTO(chip->timeout, reg);
        }
 
@@ -1233,14 +1292,13 @@ static int setup(struct spi_device *spi)
        uint tx_thres = TX_THRESH_DFLT;
        uint rx_thres = RX_THRESH_DFLT;
 
-       if (drv_data->ssp_type != PXA25x_SSP
+       if (!pxa25x_ssp_comp(drv_data)
                && (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
                dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
                                "b/w not 4-32 for type non-PXA25x_SSP\n",
                                drv_data->ssp_type, spi->bits_per_word);
                return -EINVAL;
-       }
-       else if (drv_data->ssp_type == PXA25x_SSP
+       } else if (pxa25x_ssp_comp(drv_data)
                        && (spi->bits_per_word < 4
                                || spi->bits_per_word > 16)) {
                dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
@@ -1259,7 +1317,17 @@ static int setup(struct spi_device *spi)
                        return -ENOMEM;
                }
 
-               chip->gpio_cs = -1;
+               if (drv_data->ssp_type == CE4100_SSP) {
+                       if (spi->chip_select > 4) {
+                               dev_err(&spi->dev, "failed setup: "
+                               "cs number must not be > 4.\n");
+                               kfree(chip);
+                               return -EINVAL;
+                       }
+
+                       chip->frm = spi->chip_select;
+               } else
+                       chip->gpio_cs = -1;
                chip->enable_dma = 0;
                chip->timeout = TIMOUT_DFLT;
                chip->dma_burst_size = drv_data->master_info->enable_dma ?
@@ -1315,7 +1383,7 @@ static int setup(struct spi_device *spi)
                        | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
 
        /* NOTE:  PXA25x_SSP _could_ use external clocking ... */
-       if (drv_data->ssp_type != PXA25x_SSP)
+       if (!pxa25x_ssp_comp(drv_data))
                dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
                        clk_get_rate(ssp->clk)
                                / (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
@@ -1350,23 +1418,27 @@ static int setup(struct spi_device *spi)
 
        spi_set_ctldata(spi, chip);
 
+       if (drv_data->ssp_type == CE4100_SSP)
+               return 0;
+
        return setup_cs(spi, chip, chip_info);
 }
 
 static void cleanup(struct spi_device *spi)
 {
        struct chip_data *chip = spi_get_ctldata(spi);
+       struct driver_data *drv_data = spi_master_get_devdata(spi->master);
 
        if (!chip)
                return;
 
-       if (gpio_is_valid(chip->gpio_cs))
+       if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs))
                gpio_free(chip->gpio_cs);
 
        kfree(chip);
 }
 
-static int __init init_queue(struct driver_data *drv_data)
+static int __devinit init_queue(struct driver_data *drv_data)
 {
        INIT_LIST_HEAD(&drv_data->queue);
        spin_lock_init(&drv_data->lock);
@@ -1454,7 +1526,7 @@ static int destroy_queue(struct driver_data *drv_data)
        return 0;
 }
 
-static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct pxa2xx_spi_master *platform_info;
@@ -1484,6 +1556,10 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
        drv_data->pdev = pdev;
        drv_data->ssp = ssp;
 
+       master->dev.parent = &pdev->dev;
+#ifdef CONFIG_OF
+       master->dev.of_node = pdev->dev.of_node;
+#endif
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 
@@ -1500,7 +1576,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 
        drv_data->ioaddr = ssp->mmio_base;
        drv_data->ssdr_physical = ssp->phys_base + SSDR;
-       if (ssp->type == PXA25x_SSP) {
+       if (pxa25x_ssp_comp(drv_data)) {
                drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
                drv_data->dma_cr1 = 0;
                drv_data->clear_sr = SSSR_ROR;
@@ -1512,7 +1588,8 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
                drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
        }
 
-       status = request_irq(ssp->irq, ssp_int, 0, dev_name(dev), drv_data);
+       status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev),
+                       drv_data);
        if (status < 0) {
                dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq);
                goto out_error_master_alloc;
@@ -1561,7 +1638,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
                        | SSCR0_Motorola
                        | SSCR0_DataSize(8),
                        drv_data->ioaddr);
-       if (drv_data->ssp_type != PXA25x_SSP)
+       if (!pxa25x_ssp_comp(drv_data))
                write_SSTO(0, drv_data->ioaddr);
        write_SSPSP(0, drv_data->ioaddr);
 
@@ -1723,13 +1800,14 @@ static struct platform_driver driver = {
                .pm     = &pxa2xx_spi_pm_ops,
 #endif
        },
+       .probe = pxa2xx_spi_probe,
        .remove = pxa2xx_spi_remove,
        .shutdown = pxa2xx_spi_shutdown,
 };
 
 static int __init pxa2xx_spi_init(void)
 {
-       return platform_driver_probe(&driver, pxa2xx_spi_probe);
+       return platform_driver_register(&driver);
 }
 subsys_initcall(pxa2xx_spi_init);
 
diff --git a/drivers/spi/pxa2xx_spi_pci.c b/drivers/spi/pxa2xx_spi_pci.c
new file mode 100644 (file)
index 0000000..351d8a3
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * CE4100's SPI device is more or less the same one as found on PXA
+ *
+ */
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/spi/pxa2xx_spi.h>
+
+struct awesome_struct {
+       struct ssp_device ssp;
+       struct platform_device spi_pdev;
+       struct pxa2xx_spi_master spi_pdata;
+};
+
+static DEFINE_MUTEX(ssp_lock);
+static LIST_HEAD(ssp_list);
+
+struct ssp_device *pxa_ssp_request(int port, const char *label)
+{
+       struct ssp_device *ssp = NULL;
+
+       mutex_lock(&ssp_lock);
+
+       list_for_each_entry(ssp, &ssp_list, node) {
+               if (ssp->port_id == port && ssp->use_count == 0) {
+                       ssp->use_count++;
+                       ssp->label = label;
+                       break;
+               }
+       }
+
+       mutex_unlock(&ssp_lock);
+
+       if (&ssp->node == &ssp_list)
+               return NULL;
+
+       return ssp;
+}
+EXPORT_SYMBOL_GPL(pxa_ssp_request);
+
+void pxa_ssp_free(struct ssp_device *ssp)
+{
+       mutex_lock(&ssp_lock);
+       if (ssp->use_count) {
+               ssp->use_count--;
+               ssp->label = NULL;
+       } else
+               dev_err(&ssp->pdev->dev, "device already free\n");
+       mutex_unlock(&ssp_lock);
+}
+EXPORT_SYMBOL_GPL(pxa_ssp_free);
+
+static void plat_dev_release(struct device *dev)
+{
+       struct awesome_struct *as = container_of(dev,
+                       struct awesome_struct, spi_pdev.dev);
+
+       of_device_node_put(&as->spi_pdev.dev);
+}
+
+static int __devinit ce4100_spi_probe(struct pci_dev *dev,
+               const struct pci_device_id *ent)
+{
+       int ret;
+       resource_size_t phys_beg;
+       resource_size_t phys_len;
+       struct awesome_struct *spi_info;
+       struct platform_device *pdev;
+       struct pxa2xx_spi_master *spi_pdata;
+       struct ssp_device *ssp;
+
+       ret = pci_enable_device(dev);
+       if (ret)
+               return ret;
+
+       phys_beg = pci_resource_start(dev, 0);
+       phys_len = pci_resource_len(dev, 0);
+
+       if (!request_mem_region(phys_beg, phys_len,
+                               "CE4100 SPI")) {
+               dev_err(&dev->dev, "Can't request register space.\n");
+               ret = -EBUSY;
+               return ret;
+       }
+
+       spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
+       if (!spi_info) {
+               ret = -ENOMEM;
+               goto err_kz;
+       }
+       ssp = &spi_info->ssp;
+       pdev = &spi_info->spi_pdev;
+       spi_pdata =  &spi_info->spi_pdata;
+
+       pdev->name = "pxa2xx-spi";
+       pdev->id = dev->devfn;
+       pdev->dev.parent = &dev->dev;
+       pdev->dev.platform_data = &spi_info->spi_pdata;
+
+#ifdef CONFIG_OF
+       pdev->dev.of_node = dev->dev.of_node;
+#endif
+       pdev->dev.release = plat_dev_release;
+
+       spi_pdata->num_chipselect = dev->devfn;
+
+       ssp->phys_base = pci_resource_start(dev, 0);
+       ssp->mmio_base = ioremap(phys_beg, phys_len);
+       if (!ssp->mmio_base) {
+               dev_err(&pdev->dev, "failed to ioremap() registers\n");
+               ret = -EIO;
+               goto err_remap;
+       }
+       ssp->irq = dev->irq;
+       ssp->port_id = pdev->id;
+       ssp->type = PXA25x_SSP;
+
+       mutex_lock(&ssp_lock);
+       list_add(&ssp->node, &ssp_list);
+       mutex_unlock(&ssp_lock);
+
+       pci_set_drvdata(dev, spi_info);
+
+       ret = platform_device_register(pdev);
+       if (ret)
+               goto err_dev_add;
+
+       return ret;
+
+err_dev_add:
+       pci_set_drvdata(dev, NULL);
+       mutex_lock(&ssp_lock);
+       list_del(&ssp->node);
+       mutex_unlock(&ssp_lock);
+       iounmap(ssp->mmio_base);
+
+err_remap:
+       kfree(spi_info);
+
+err_kz:
+       release_mem_region(phys_beg, phys_len);
+
+       return ret;
+}
+
+static void __devexit ce4100_spi_remove(struct pci_dev *dev)
+{
+       struct awesome_struct *spi_info;
+       struct platform_device *pdev;
+       struct ssp_device *ssp;
+
+       spi_info = pci_get_drvdata(dev);
+
+       ssp = &spi_info->ssp;
+       pdev = &spi_info->spi_pdev;
+
+       platform_device_unregister(pdev);
+
+       iounmap(ssp->mmio_base);
+       release_mem_region(pci_resource_start(dev, 0),
+                       pci_resource_len(dev, 0));
+
+       mutex_lock(&ssp_lock);
+       list_del(&ssp->node);
+       mutex_unlock(&ssp_lock);
+
+       pci_set_drvdata(dev, NULL);
+       pci_disable_device(dev);
+       kfree(spi_info);
+}
+
+static struct pci_device_id ce4100_spi_devices[] __devinitdata = {
+
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) },
+       { },
+};
+MODULE_DEVICE_TABLE(pci, ce4100_spi_devices);
+
+static struct pci_driver ce4100_spi_driver = {
+       .name           = "ce4100_spi",
+       .id_table       = ce4100_spi_devices,
+       .probe          = ce4100_spi_probe,
+       .remove         = __devexit_p(ce4100_spi_remove),
+};
+
+static int __init ce4100_spi_init(void)
+{
+       return pci_register_driver(&ce4100_spi_driver);
+}
+module_init(ce4100_spi_init);
+
+static void __exit ce4100_spi_exit(void)
+{
+       pci_unregister_driver(&ce4100_spi_driver);
+}
+module_exit(ce4100_spi_exit);
+
+MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
index b02d0cbce89049e003fe8300421adeed847e92ce..34bb17f030197d0ab395e17b75475ff30c123ec5 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/spi/spi.h>
 #include <linux/of_spi.h>
+#include <linux/pm_runtime.h>
 
 static void spidev_release(struct device *dev)
 {
@@ -100,9 +101,8 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
-#ifdef CONFIG_PM
-
-static int spi_suspend(struct device *dev, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int spi_legacy_suspend(struct device *dev, pm_message_t message)
 {
        int                     value = 0;
        struct spi_driver       *drv = to_spi_driver(dev->driver);
@@ -117,7 +117,7 @@ static int spi_suspend(struct device *dev, pm_message_t message)
        return value;
 }
 
-static int spi_resume(struct device *dev)
+static int spi_legacy_resume(struct device *dev)
 {
        int                     value = 0;
        struct spi_driver       *drv = to_spi_driver(dev->driver);
@@ -132,18 +132,94 @@ static int spi_resume(struct device *dev)
        return value;
 }
 
+static int spi_pm_suspend(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_suspend(dev);
+       else
+               return spi_legacy_suspend(dev, PMSG_SUSPEND);
+}
+
+static int spi_pm_resume(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_resume(dev);
+       else
+               return spi_legacy_resume(dev);
+}
+
+static int spi_pm_freeze(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_freeze(dev);
+       else
+               return spi_legacy_suspend(dev, PMSG_FREEZE);
+}
+
+static int spi_pm_thaw(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_thaw(dev);
+       else
+               return spi_legacy_resume(dev);
+}
+
+static int spi_pm_poweroff(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_poweroff(dev);
+       else
+               return spi_legacy_suspend(dev, PMSG_HIBERNATE);
+}
+
+static int spi_pm_restore(struct device *dev)
+{
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm)
+               return pm_generic_restore(dev);
+       else
+               return spi_legacy_resume(dev);
+}
 #else
-#define spi_suspend    NULL
-#define spi_resume     NULL
+#define spi_pm_suspend NULL
+#define spi_pm_resume  NULL
+#define spi_pm_freeze  NULL
+#define spi_pm_thaw    NULL
+#define spi_pm_poweroff        NULL
+#define spi_pm_restore NULL
 #endif
 
+static const struct dev_pm_ops spi_pm = {
+       .suspend = spi_pm_suspend,
+       .resume = spi_pm_resume,
+       .freeze = spi_pm_freeze,
+       .thaw = spi_pm_thaw,
+       .poweroff = spi_pm_poweroff,
+       .restore = spi_pm_restore,
+       SET_RUNTIME_PM_OPS(
+               pm_generic_runtime_suspend,
+               pm_generic_runtime_resume,
+               pm_generic_runtime_idle
+       )
+};
+
 struct bus_type spi_bus_type = {
        .name           = "spi",
        .dev_attrs      = spi_dev_attrs,
        .match          = spi_match_device,
        .uevent         = spi_uevent,
-       .suspend        = spi_suspend,
-       .resume         = spi_resume,
+       .pm             = &spi_pm,
 };
 EXPORT_SYMBOL_GPL(spi_bus_type);
 
index 55a38e2c6c137a0530b107bdfe5bc0ac0dd94e7b..9469564e6888e3a2715f82c21a330ca98759ec45 100644 (file)
@@ -66,7 +66,6 @@ enum spi_imx_devtype {
        SPI_IMX_VER_0_5,
        SPI_IMX_VER_0_7,
        SPI_IMX_VER_2_3,
-       SPI_IMX_VER_AUTODETECT,
 };
 
 struct spi_imx_data;
@@ -720,9 +719,6 @@ static void spi_imx_cleanup(struct spi_device *spi)
 
 static struct platform_device_id spi_imx_devtype[] = {
        {
-               .name = DRIVER_NAME,
-               .driver_data = SPI_IMX_VER_AUTODETECT,
-       }, {
                .name = "imx1-cspi",
                .driver_data = SPI_IMX_VER_IMX1,
        }, {
@@ -802,30 +798,8 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
 
        init_completion(&spi_imx->xfer_done);
 
-       if (pdev->id_entry->driver_data == SPI_IMX_VER_AUTODETECT) {
-               if (cpu_is_mx25() || cpu_is_mx35())
-                       spi_imx->devtype_data =
-                               spi_imx_devtype_data[SPI_IMX_VER_0_7];
-               else if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35())
-                       spi_imx->devtype_data =
-                               spi_imx_devtype_data[SPI_IMX_VER_0_4];
-               else if (cpu_is_mx27() || cpu_is_mx21())
-                       spi_imx->devtype_data =
-                               spi_imx_devtype_data[SPI_IMX_VER_0_0];
-               else if (cpu_is_mx1())
-                       spi_imx->devtype_data =
-                               spi_imx_devtype_data[SPI_IMX_VER_IMX1];
-               else
-                       BUG();
-       } else
-               spi_imx->devtype_data =
-                       spi_imx_devtype_data[pdev->id_entry->driver_data];
-
-       if (!spi_imx->devtype_data.intctrl) {
-               dev_err(&pdev->dev, "no support for this device compiled in\n");
-               ret = -ENODEV;
-               goto out_gpio_free;
-       }
+       spi_imx->devtype_data =
+               spi_imx_devtype_data[pdev->id_entry->driver_data];
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -847,7 +821,7 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
        }
 
        spi_imx->irq = platform_get_irq(pdev, 0);
-       if (spi_imx->irq <= 0) {
+       if (spi_imx->irq < 0) {
                ret = -EINVAL;
                goto out_iounmap;
        }
index dff63be0d0a8c7b23205d9374c209e3914805bfb..d5be18b3078c4e3440c45d1bd3fed1b66fc44491 100644 (file)
@@ -449,7 +449,7 @@ err_iomap:
        release_mem_region(hw->res->start, resource_size(hw->res));
        kfree(hw->ioarea);
 err_pdata:
-       spi_master_put(hw->master);;
+       spi_master_put(hw->master);
 
 err_nomem:
        return err;
index 58e187f45ec73f9eabb42d4ebafcfb930a4450dc..79e48d451137db07e1a5420e0417460c28aaec52 100644 (file)
@@ -267,7 +267,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
        if (reg_spsr_val & SPSR_FI_BIT) {
                /* disable FI & RFI interrupts */
                pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
-                                  SPCR_FIE_BIT | SPCR_TFIE_BIT);
+                                  SPCR_FIE_BIT | SPCR_RFIE_BIT);
 
                /* transfer is completed;inform pch_spi_process_messages */
                data->transfer_complete = true;
@@ -677,15 +677,15 @@ static void pch_spi_set_ir(struct pch_spi_data *data)
 {
        /* enable interrupts */
        if ((data->bpw_len) > PCH_MAX_FIFO_DEPTH) {
-               /* set receive threhold to PCH_RX_THOLD */
+               /* set receive threshold to PCH_RX_THOLD */
                pch_spi_setclr_reg(data->master, PCH_SPCR,
-                                  PCH_RX_THOLD << SPCR_TFIC_FIELD,
-                                  ~MASK_TFIC_SPCR_BITS);
+                                  PCH_RX_THOLD << SPCR_RFIC_FIELD,
+                                  ~MASK_RFIC_SPCR_BITS);
                /* enable FI and RFI interrupts */
                pch_spi_setclr_reg(data->master, PCH_SPCR,
-                                  SPCR_RFIE_BIT | SPCR_TFIE_BIT, 0);
+                                  SPCR_RFIE_BIT | SPCR_FIE_BIT, 0);
        } else {
-               /* set receive threhold to maximum */
+               /* set receive threshold to maximum */
                pch_spi_setclr_reg(data->master, PCH_SPCR,
                                   PCH_RX_THOLD_MAX << SPCR_TFIC_FIELD,
                                   ~MASK_TFIC_SPCR_BITS);
index 80f2db5bcfd6e669bdd136c25f2d04ebb51d4595..7adaef62a99122a0e7e7427207f2e47132d33469 100644 (file)
@@ -1,26 +1,27 @@
 /*
- * xilinx_spi.c
- *
  * Xilinx SPI controller driver (master mode only)
  *
  * Author: MontaVista Software, Inc.
  *     source@mvista.com
  *
- * 2002-2007 (c) MontaVista Software, Inc.  This file is licensed under the
- * terms of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
+ * Copyright (c) 2010 Secret Lab Technologies, Ltd.
+ * Copyright (c) 2009 Intel Corporation
+ * 2002-2007 (c) MontaVista Software, Inc.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  */
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-
+#include <linux/of.h>
+#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
-#include <linux/io.h>
-
-#include "xilinx_spi.h"
 #include <linux/spi/xilinx_spi.h>
+#include <linux/io.h>
 
 #define XILINX_SPI_NAME "xilinx_spi"
 
@@ -350,19 +351,22 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id xilinx_spi_of_match[] = {
+       { .compatible = "xlnx,xps-spi-2.00.a", },
+       { .compatible = "xlnx,xps-spi-2.00.b", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
+#endif
+
 struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
-       u32 irq, s16 bus_num)
+       u32 irq, s16 bus_num, int num_cs, int little_endian, int bits_per_word)
 {
        struct spi_master *master;
        struct xilinx_spi *xspi;
-       struct xspi_platform_data *pdata = dev->platform_data;
        int ret;
 
-       if (!pdata) {
-               dev_err(dev, "No platform data attached\n");
-               return NULL;
-       }
-
        master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
        if (!master)
                return NULL;
@@ -389,21 +393,21 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
        }
 
        master->bus_num = bus_num;
-       master->num_chipselect = pdata->num_chipselect;
+       master->num_chipselect = num_cs;
 #ifdef CONFIG_OF
        master->dev.of_node = dev->of_node;
 #endif
 
        xspi->mem = *mem;
        xspi->irq = irq;
-       if (pdata->little_endian) {
+       if (little_endian) {
                xspi->read_fn = xspi_read32;
                xspi->write_fn = xspi_write32;
        } else {
                xspi->read_fn = xspi_read32_be;
                xspi->write_fn = xspi_write32_be;
        }
-       xspi->bits_per_word = pdata->bits_per_word;
+       xspi->bits_per_word = bits_per_word;
        if (xspi->bits_per_word == 8) {
                xspi->tx_fn = xspi_tx8;
                xspi->rx_fn = xspi_rx8;
@@ -462,6 +466,97 @@ void xilinx_spi_deinit(struct spi_master *master)
 }
 EXPORT_SYMBOL(xilinx_spi_deinit);
 
+static int __devinit xilinx_spi_probe(struct platform_device *dev)
+{
+       struct xspi_platform_data *pdata;
+       struct resource *r;
+       int irq, num_cs = 0, little_endian = 0, bits_per_word = 8;
+       struct spi_master *master;
+       u8 i;
+
+       pdata = dev->dev.platform_data;
+       if (pdata) {
+               num_cs = pdata->num_chipselect;
+               little_endian = pdata->little_endian;
+               bits_per_word = pdata->bits_per_word;
+       }
+
+#ifdef CONFIG_OF
+       if (dev->dev.of_node) {
+               const __be32 *prop;
+               int len;
+
+               /* number of slave select bits is required */
+               prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits",
+                                      &len);
+               if (prop && len >= sizeof(*prop))
+                       num_cs = __be32_to_cpup(prop);
+       }
+#endif
+
+       if (!num_cs) {
+               dev_err(&dev->dev, "Missing slave select configuration data\n");
+               return -EINVAL;
+       }
+
+
+       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!r)
+               return -ENODEV;
+
+       irq = platform_get_irq(dev, 0);
+       if (irq < 0)
+               return -ENXIO;
+
+       master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs,
+                                little_endian, bits_per_word);
+       if (!master)
+               return -ENODEV;
+
+       if (pdata) {
+               for (i = 0; i < pdata->num_devices; i++)
+                       spi_new_device(master, pdata->devices + i);
+       }
+
+       platform_set_drvdata(dev, master);
+       return 0;
+}
+
+static int __devexit xilinx_spi_remove(struct platform_device *dev)
+{
+       xilinx_spi_deinit(platform_get_drvdata(dev));
+       platform_set_drvdata(dev, 0);
+
+       return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:" XILINX_SPI_NAME);
+
+static struct platform_driver xilinx_spi_driver = {
+       .probe = xilinx_spi_probe,
+       .remove = __devexit_p(xilinx_spi_remove),
+       .driver = {
+               .name = XILINX_SPI_NAME,
+               .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+               .of_match_table = xilinx_spi_of_match,
+#endif
+       },
+};
+
+static int __init xilinx_spi_pltfm_init(void)
+{
+       return platform_driver_register(&xilinx_spi_driver);
+}
+module_init(xilinx_spi_pltfm_init);
+
+static void __exit xilinx_spi_pltfm_exit(void)
+{
+       platform_driver_unregister(&xilinx_spi_driver);
+}
+module_exit(xilinx_spi_pltfm_exit);
+
 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
 MODULE_DESCRIPTION("Xilinx SPI driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h
deleted file mode 100644 (file)
index d211acc..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Xilinx SPI device driver API and platform data header file
- *
- * Copyright (c) 2009 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _XILINX_SPI_H_
-#define _XILINX_SPI_H_
-
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
-
-#define XILINX_SPI_NAME "xilinx_spi"
-
-struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
-       u32 irq, s16 bus_num);
-
-void xilinx_spi_deinit(struct spi_master *master);
-#endif
diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c
deleted file mode 100644 (file)
index b66c2db..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Xilinx SPI OF device driver
- *
- * Copyright (c) 2009 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Supports:
- * Xilinx SPI devices as OF devices
- *
- * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/of_spi.h>
-
-#include <linux/spi/xilinx_spi.h>
-#include "xilinx_spi.h"
-
-
-static int __devinit xilinx_spi_of_probe(struct platform_device *ofdev,
-       const struct of_device_id *match)
-{
-       struct spi_master *master;
-       struct xspi_platform_data *pdata;
-       struct resource r_mem;
-       struct resource r_irq;
-       int rc = 0;
-       const u32 *prop;
-       int len;
-
-       rc = of_address_to_resource(ofdev->dev.of_node, 0, &r_mem);
-       if (rc) {
-               dev_warn(&ofdev->dev, "invalid address\n");
-               return rc;
-       }
-
-       rc = of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq);
-       if (rc == NO_IRQ) {
-               dev_warn(&ofdev->dev, "no IRQ found\n");
-               return -ENODEV;
-       }
-
-       ofdev->dev.platform_data =
-               kzalloc(sizeof(struct xspi_platform_data), GFP_KERNEL);
-       pdata = ofdev->dev.platform_data;
-       if (!pdata)
-               return -ENOMEM;
-
-       /* number of slave select bits is required */
-       prop = of_get_property(ofdev->dev.of_node, "xlnx,num-ss-bits", &len);
-       if (!prop || len < sizeof(*prop)) {
-               dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
-               return -EINVAL;
-       }
-       pdata->num_chipselect = *prop;
-       pdata->bits_per_word = 8;
-       master = xilinx_spi_init(&ofdev->dev, &r_mem, r_irq.start, -1);
-       if (!master)
-               return -ENODEV;
-
-       dev_set_drvdata(&ofdev->dev, master);
-
-       return 0;
-}
-
-static int __devexit xilinx_spi_remove(struct platform_device *ofdev)
-{
-       xilinx_spi_deinit(dev_get_drvdata(&ofdev->dev));
-       dev_set_drvdata(&ofdev->dev, 0);
-       kfree(ofdev->dev.platform_data);
-       ofdev->dev.platform_data = NULL;
-       return 0;
-}
-
-static int __exit xilinx_spi_of_remove(struct platform_device *op)
-{
-       return xilinx_spi_remove(op);
-}
-
-static const struct of_device_id xilinx_spi_of_match[] = {
-       { .compatible = "xlnx,xps-spi-2.00.a", },
-       { .compatible = "xlnx,xps-spi-2.00.b", },
-       {}
-};
-
-MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
-
-static struct of_platform_driver xilinx_spi_of_driver = {
-       .probe = xilinx_spi_of_probe,
-       .remove = __exit_p(xilinx_spi_of_remove),
-       .driver = {
-               .name = "xilinx-xps-spi",
-               .owner = THIS_MODULE,
-               .of_match_table = xilinx_spi_of_match,
-       },
-};
-
-static int __init xilinx_spi_of_init(void)
-{
-       return of_register_platform_driver(&xilinx_spi_of_driver);
-}
-module_init(xilinx_spi_of_init);
-
-static void __exit xilinx_spi_of_exit(void)
-{
-       of_unregister_platform_driver(&xilinx_spi_of_driver);
-}
-module_exit(xilinx_spi_of_exit);
-
-MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
-MODULE_DESCRIPTION("Xilinx SPI platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/xilinx_spi_pltfm.c b/drivers/spi/xilinx_spi_pltfm.c
deleted file mode 100644 (file)
index 24debac..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Support for Xilinx SPI platform devices
- * Copyright (c) 2009 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Supports:
- * Xilinx SPI devices as platform devices
- *
- * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
-#include <linux/spi/xilinx_spi.h>
-
-#include "xilinx_spi.h"
-
-static int __devinit xilinx_spi_probe(struct platform_device *dev)
-{
-       struct xspi_platform_data *pdata;
-       struct resource *r;
-       int irq;
-       struct spi_master *master;
-       u8 i;
-
-       pdata = dev->dev.platform_data;
-       if (!pdata)
-               return -ENODEV;
-
-       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!r)
-               return -ENODEV;
-
-       irq = platform_get_irq(dev, 0);
-       if (irq < 0)
-               return -ENXIO;
-
-       master = xilinx_spi_init(&dev->dev, r, irq, dev->id);
-       if (!master)
-               return -ENODEV;
-
-       for (i = 0; i < pdata->num_devices; i++)
-               spi_new_device(master, pdata->devices + i);
-
-       platform_set_drvdata(dev, master);
-       return 0;
-}
-
-static int __devexit xilinx_spi_remove(struct platform_device *dev)
-{
-       xilinx_spi_deinit(platform_get_drvdata(dev));
-       platform_set_drvdata(dev, 0);
-
-       return 0;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:" XILINX_SPI_NAME);
-
-static struct platform_driver xilinx_spi_driver = {
-       .probe  = xilinx_spi_probe,
-       .remove = __devexit_p(xilinx_spi_remove),
-       .driver = {
-               .name = XILINX_SPI_NAME,
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init xilinx_spi_pltfm_init(void)
-{
-       return platform_driver_register(&xilinx_spi_driver);
-}
-module_init(xilinx_spi_pltfm_init);
-
-static void __exit xilinx_spi_pltfm_exit(void)
-{
-       platform_driver_unregister(&xilinx_spi_driver);
-}
-module_exit(xilinx_spi_pltfm_exit);
-
-MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
-MODULE_DESCRIPTION("Xilinx SPI platform driver");
-MODULE_LICENSE("GPL v2");
index 971844bbee284a141f36d6221a29fb793a6574a9..9bcf149c4260ad3a8020caccc98801fff40664de 100644 (file)
@@ -377,7 +377,7 @@ static int init_timing_params(unsigned int new_duty_cycle,
        duty_cycle = new_duty_cycle;
        freq = new_freq;
 
-       loops_per_sec = current_cpu_data.loops_per_jiffy;
+       loops_per_sec = __this_cpu_read(cpu.info.loops_per_jiffy);
        loops_per_sec *= HZ;
 
        /* How many clocks in a microsecond?, avoiding long long divide */
@@ -398,7 +398,7 @@ static int init_timing_params(unsigned int new_duty_cycle,
        dprintk("in init_timing_params, freq=%d, duty_cycle=%d, "
                "clk/jiffy=%ld, pulse=%ld, space=%ld, "
                "conv_us_to_clocks=%ld\n",
-               freq, duty_cycle, current_cpu_data.loops_per_jiffy,
+               freq, duty_cycle, __this_cpu_read(cpu_info.loops_per_jiffy),
                pulse_width, space_width, conv_us_to_clocks);
        return 0;
 }
index cc8d2840f9b629f7dd432f8e094377d7a57133bd..56d3a4e5622f27bb5d2ce34a23a9711516a065fd 100644 (file)
@@ -1325,8 +1325,8 @@ static void pohmelfs_put_super(struct super_block *sb)
        }
 
        psb->trans_scan_timeout = psb->drop_scan_timeout = 0;
-       cancel_rearming_delayed_work(&psb->dwork);
-       cancel_rearming_delayed_work(&psb->drop_dwork);
+       cancel_delayed_work_sync(&psb->dwork);
+       cancel_delayed_work_sync(&psb->drop_dwork);
        flush_scheduled_work();
 
        dprintk("%s: stopped workqueues.\n", __func__);
index 65b231178f0580d30a4233e17bf31eb73c7df6f7..1b34a87716418b8af6248d0540d9958f2b0cbd2e 100644 (file)
@@ -78,10 +78,10 @@ void speakup_fake_down_arrow(void)
        /* don't change CPU */
        preempt_disable();
 
-       __get_cpu_var(reporting_keystroke) = true;
+       __this_cpu_write(reporting_keystroke, true);
        input_report_key(virt_keyboard, KEY_DOWN, PRESSED);
        input_report_key(virt_keyboard, KEY_DOWN, RELEASED);
-       __get_cpu_var(reporting_keystroke) = false;
+       __this_cpu_write(reporting_keystroke, false);
 
        /* reenable preemption */
        preempt_enable();
@@ -95,10 +95,5 @@ void speakup_fake_down_arrow(void)
         */
 bool speakup_fake_key_pressed(void)
 {
-       bool is_pressed;
-
-       is_pressed = get_cpu_var(reporting_keystroke);
-       put_cpu_var(reporting_keystroke);
-
-       return is_pressed;
+       return this_cpu_read(reporting_keystroke);
 }
index f383cb42b1d76c779f5fa91f5cac8d3599f16bba..a845f8b8382f1d1052f34f57665d46bf1d871132 100644 (file)
@@ -1247,7 +1247,7 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance,
        mutex_unlock(&instance->poll_state_serialize);
 
        if (is_polling)
-               cancel_rearming_delayed_work(&instance->poll_work);
+               cancel_delayed_work_sync(&instance->poll_work);
 
        usb_kill_urb(instance->snd_urb);
        usb_kill_urb(instance->rcv_urb);
index 4716e707de59ceb7e3559ca4b9f1f51b5694fa13..0842cfbf60cfcf74ec08b835d469c1f1c8f26ada 100644 (file)
@@ -139,7 +139,8 @@ struct speedtch_instance_data {
 
        struct speedtch_params params; /* set in probe, constant afterwards */
 
-       struct delayed_work status_checker;
+       struct timer_list status_check_timer;
+       struct work_struct status_check_work;
 
        unsigned char last_status;
 
@@ -498,7 +499,7 @@ static void speedtch_check_status(struct work_struct *work)
 {
        struct speedtch_instance_data *instance =
                container_of(work, struct speedtch_instance_data,
-                            status_checker.work);
+                            status_check_work);
        struct usbatm_data *usbatm = instance->usbatm;
        struct atm_dev *atm_dev = usbatm->atm_dev;
        unsigned char *buf = instance->scratch_buffer;
@@ -575,11 +576,11 @@ static void speedtch_status_poll(unsigned long data)
 {
        struct speedtch_instance_data *instance = (void *)data;
 
-       schedule_delayed_work(&instance->status_checker, 0);
+       schedule_work(&instance->status_check_work);
 
        /* The following check is racy, but the race is harmless */
        if (instance->poll_delay < MAX_POLL_DELAY)
-               mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(instance->poll_delay));
+               mod_timer(&instance->status_check_timer, jiffies + msecs_to_jiffies(instance->poll_delay));
        else
                atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n");
 }
@@ -595,7 +596,7 @@ static void speedtch_resubmit_int(unsigned long data)
        if (int_urb) {
                ret = usb_submit_urb(int_urb, GFP_ATOMIC);
                if (!ret)
-                       schedule_delayed_work(&instance->status_checker, 0);
+                       schedule_work(&instance->status_check_work);
                else {
                        atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
                        mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
@@ -624,7 +625,7 @@ static void speedtch_handle_int(struct urb *int_urb)
        }
 
        if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) {
-               del_timer(&instance->status_checker.timer);
+               del_timer(&instance->status_check_timer);
                atm_info(usbatm, "DSL line goes up\n");
        } else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) {
                atm_info(usbatm, "DSL line goes down\n");
@@ -640,7 +641,7 @@ static void speedtch_handle_int(struct urb *int_urb)
 
        if ((int_urb = instance->int_urb)) {
                ret = usb_submit_urb(int_urb, GFP_ATOMIC);
-               schedule_delayed_work(&instance->status_checker, 0);
+               schedule_work(&instance->status_check_work);
                if (ret < 0) {
                        atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
                        goto fail;
@@ -686,7 +687,7 @@ static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_de
        }
 
        /* Start status polling */
-       mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(1000));
+       mod_timer(&instance->status_check_timer, jiffies + msecs_to_jiffies(1000));
 
        return 0;
 }
@@ -698,7 +699,7 @@ static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_de
 
        atm_dbg(usbatm, "%s entered\n", __func__);
 
-       del_timer_sync(&instance->status_checker.timer);
+       del_timer_sync(&instance->status_check_timer);
 
        /*
         * Since resubmit_timer and int_urb can schedule themselves and
@@ -717,7 +718,7 @@ static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_de
        del_timer_sync(&instance->resubmit_timer);
        usb_free_urb(int_urb);
 
-       flush_scheduled_work();
+       flush_work_sync(&instance->status_check_work);
 }
 
 static int speedtch_pre_reset(struct usb_interface *intf)
@@ -869,10 +870,11 @@ static int speedtch_bind(struct usbatm_data *usbatm,
 
        usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0);
 
-       INIT_DELAYED_WORK(&instance->status_checker, speedtch_check_status);
+       INIT_WORK(&instance->status_check_work, speedtch_check_status);
+       init_timer(&instance->status_check_timer);
 
-       instance->status_checker.timer.function = speedtch_status_poll;
-       instance->status_checker.timer.data = (unsigned long)instance;
+       instance->status_check_timer.function = speedtch_status_poll;
+       instance->status_check_timer.data = (unsigned long)instance;
        instance->last_status = 0xff;
        instance->poll_delay = MIN_POLL_DELAY;
 
index b9278a1fb9e57d9f77a99dcfc4b6b1cb04d01821..fca61720b8733140c805c36fd8b7398fd58fac12 100644 (file)
@@ -375,7 +375,7 @@ static int usb_unbind_interface(struct device *dev)
                 * Just re-enable it without affecting the endpoint toggles.
                 */
                usb_enable_interface(udev, intf, false);
-       } else if (!error && intf->dev.power.status == DPM_ON) {
+       } else if (!error && !intf->dev.power.in_suspend) {
                r = usb_set_interface(udev, intf->altsetting[0].
                                desc.bInterfaceNumber, 0);
                if (r < 0)
@@ -960,7 +960,7 @@ void usb_rebind_intf(struct usb_interface *intf)
        }
 
        /* Try to rebind the interface */
-       if (intf->dev.power.status == DPM_ON) {
+       if (!intf->dev.power.in_suspend) {
                intf->needs_binding = 0;
                rc = device_attach(&intf->dev);
                if (rc < 0)
@@ -1107,8 +1107,7 @@ static int usb_resume_interface(struct usb_device *udev,
        if (intf->condition == USB_INTERFACE_UNBOUND) {
 
                /* Carry out a deferred switch to altsetting 0 */
-               if (intf->needs_altsetting0 &&
-                               intf->dev.power.status == DPM_ON) {
+               if (intf->needs_altsetting0 && !intf->dev.power.in_suspend) {
                        usb_set_interface(udev, intf->altsetting[0].
                                        desc.bInterfaceNumber, 0);
                        intf->needs_altsetting0 = 0;
index e3454fe46b47b6d1dd77500acd2e51bbf6691cce..1eda968b5644249ac3a882c2c9756d573df63ffa 100644 (file)
@@ -839,11 +839,9 @@ void gether_cleanup(void)
                return;
 
        unregister_netdev(the_dev->net);
+       flush_work_sync(&the_dev->work);
        free_netdev(the_dev->net);
 
-       /* assuming we used keventd, it must quiesce too */
-       flush_scheduled_work();
-
        the_dev = NULL;
 }
 
index 9751647665df4e6ebc95d41969c45dcc27ed2380..759a12ff8048b64dec471ee18a1f2e4a937ae209 100644 (file)
@@ -901,7 +901,8 @@ static void ohci_stop (struct usb_hcd *hcd)
 
        ohci_dump (ohci, 1);
 
-       flush_scheduled_work();
+       if (quirk_nec(ohci))
+               flush_work_sync(&ohci->nec_work);
 
        ohci_usb_reset (ohci);
        ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
index 9e8639d4e862b65a2b23bc27a29fd09ba0b60ec1..b0176e4569e03afd9bd48788449f2d3cf0a68a30 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/kobject.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/debugfs.h>
index 456969492410d716985d7be5227cd6ca4ce8ce28..e00fa1b22ecd854b7c960f5906b8ba105e5d5d1f 100644 (file)
@@ -1247,7 +1247,7 @@ static int __exit isp1301_remove(struct i2c_client *i2c)
        isp->timer.data = 0;
        set_bit(WORK_STOP, &isp->todo);
        del_timer_sync(&isp->timer);
-       flush_scheduled_work();
+       flush_work_sync(&isp->work);
 
        put_device(&i2c->dev);
        the_transceiver = NULL;
index e199b0f4f99c462f0badb595fa9290be85214868..5be866bb7a4132a1e078939abda73daecaf2e434 100644 (file)
@@ -613,9 +613,8 @@ static void oti6858_close(struct usb_serial_port *port)
        dbg("%s(): after buf_clear()", __func__);
 
        /* cancel scheduled setup */
-       cancel_delayed_work(&priv->delayed_setup_work);
-       cancel_delayed_work(&priv->delayed_write_work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&priv->delayed_setup_work);
+       cancel_delayed_work_sync(&priv->delayed_write_work);
 
        /* shutdown our urbs */
        dbg("%s(): shutting down urbs", __func__);
index 6b93ef93cb12c08179c973e31bf97ff27eb4d56b..804000183c5e8900e69aa6c1748efa106e312690 100644 (file)
@@ -75,7 +75,7 @@ int fb_deferred_io_fsync(struct file *file, int datasync)
                return 0;
 
        /* Kill off the delayed work */
-       cancel_rearming_delayed_work(&info->deferred_work);
+       cancel_delayed_work_sync(&info->deferred_work);
 
        /* Run it immediately */
        return schedule_delayed_work(&info->deferred_work, 0);
index 64dcc7439c991f704d7920897a715941bfba4c7e..90e3bdd1b7ab933de67123ec0deca8650bd9f114 100644 (file)
@@ -396,7 +396,7 @@ static void mipid_esd_start_check(struct mipid_device *md)
 static void mipid_esd_stop_check(struct mipid_device *md)
 {
        if (md->esd_check != NULL)
-               cancel_rearming_delayed_workqueue(md->esd_wq, &md->esd_work);
+               cancel_delayed_work_sync(&md->esd_work);
 }
 
 static void mipid_esd_work(struct work_struct *work)
index 4abb0b9ed653620e4d7f17c6b94749e0ca8c8593..3e6934d4bea8eb24a7a538235eaf71141c84d02f 100644 (file)
@@ -562,26 +562,24 @@ static void xenfb_init_shared_page(struct xenfb_info *info,
 static int xenfb_connect_backend(struct xenbus_device *dev,
                                 struct xenfb_info *info)
 {
-       int ret, evtchn;
+       int ret, evtchn, irq;
        struct xenbus_transaction xbt;
 
        ret = xenbus_alloc_evtchn(dev, &evtchn);
        if (ret)
                return ret;
-       ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
+       irq = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
                                        0, dev->devicetype, info);
-       if (ret < 0) {
+       if (irq < 0) {
                xenbus_free_evtchn(dev, evtchn);
                xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
-               return ret;
+               return irq;
        }
-       info->irq = ret;
-
  again:
        ret = xenbus_transaction_start(&xbt);
        if (ret) {
                xenbus_dev_fatal(dev, ret, "starting transaction");
-               return ret;
+               goto unbind_irq;
        }
        ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
                            virt_to_mfn(info->page));
@@ -603,20 +601,25 @@ static int xenfb_connect_backend(struct xenbus_device *dev,
                if (ret == -EAGAIN)
                        goto again;
                xenbus_dev_fatal(dev, ret, "completing transaction");
-               return ret;
+               goto unbind_irq;
        }
 
        xenbus_switch_state(dev, XenbusStateInitialised);
+       info->irq = irq;
        return 0;
 
  error_xenbus:
        xenbus_transaction_end(xbt, 1);
        xenbus_dev_fatal(dev, ret, "writing xenstore");
+ unbind_irq:
+       unbind_from_irqhandler(irq, info);
        return ret;
 }
 
 static void xenfb_disconnect_backend(struct xenfb_info *info)
 {
+       /* Prevent xenfb refresh */
+       info->update_wanted = 0;
        if (info->irq >= 0)
                unbind_from_irqhandler(info->irq, info);
        info->irq = -1;
index 31af0ac31a98bffc310cfb79bcaa2d7e03393e81..74681478100ae2c20442df9b4d9d7eb8df9f12c1 100644 (file)
@@ -170,6 +170,9 @@ static struct irq_info *info_for_irq(unsigned irq)
 
 static unsigned int evtchn_from_irq(unsigned irq)
 {
+       if (unlikely(WARN(irq < 0 || irq >= nr_irqs, "Invalid irq %d!\n", irq)))
+               return 0;
+
        return info_for_irq(irq)->evtchn;
 }
 
@@ -355,7 +358,7 @@ static void unmask_evtchn(int port)
                struct evtchn_unmask unmask = { .port = port };
                (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
        } else {
-               struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+               struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
 
                sync_clear_bit(port, &s->evtchn_mask[0]);
 
@@ -405,15 +408,21 @@ static int find_unbound_irq(void)
 {
        struct irq_data *data;
        int irq, res;
-       int start = get_nr_hw_irqs();
+       int bottom = get_nr_hw_irqs();
+       int top = nr_irqs-1;
 
-       if (start == nr_irqs)
+       if (bottom == nr_irqs)
                goto no_irqs;
 
-       /* nr_irqs is a magic value. Must not use it.*/
-       for (irq = nr_irqs-1; irq > start; irq--) {
+       /* This loop starts from the top of IRQ space and goes down.
+        * We need this b/c if we have a PCI device in a Xen PV guest
+        * we do not have an IO-APIC (though the backend might have them)
+        * mapped in. To not have a collision of physical IRQs with the Xen
+        * event channels start at the top of the IRQ space for virtual IRQs.
+        */
+       for (irq = top; irq > bottom; irq--) {
                data = irq_get_irq_data(irq);
-               /* only 0->15 have init'd desc; handle irq > 16 */
+               /* only 15->0 have init'd desc; handle irq > 16 */
                if (!data)
                        break;
                if (data->chip == &no_irq_chip)
@@ -424,7 +433,7 @@ static int find_unbound_irq(void)
                        return irq;
        }
 
-       if (irq == start)
+       if (irq == bottom)
                goto no_irqs;
 
        res = irq_alloc_desc_at(irq, -1);
@@ -1101,7 +1110,7 @@ static void __xen_evtchn_do_upcall(void)
 {
        int cpu = get_cpu();
        struct shared_info *s = HYPERVISOR_shared_info;
-       struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+       struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
        unsigned count;
 
        do {
@@ -1109,7 +1118,7 @@ static void __xen_evtchn_do_upcall(void)
 
                vcpu_info->evtchn_upcall_pending = 0;
 
-               if (__get_cpu_var(xed_nesting_count)++)
+               if (__this_cpu_inc_return(xed_nesting_count) - 1)
                        goto out;
 
 #ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
@@ -1141,8 +1150,8 @@ static void __xen_evtchn_do_upcall(void)
 
                BUG_ON(!irqs_disabled());
 
-               count = __get_cpu_var(xed_nesting_count);
-               __get_cpu_var(xed_nesting_count) = 0;
+               count = __this_cpu_read(xed_nesting_count);
+               __this_cpu_write(xed_nesting_count, 0);
        } while (count != 1 || vcpu_info->evtchn_upcall_pending);
 
 out:
index 5930e382959bc504c58bbb428588a372742d4aa4..2219a76e2caf08415b2e207bc23466d4154d35e0 100644 (file)
@@ -1270,12 +1270,10 @@ static inline void check_irqs_on(void)
 static void bh_lru_install(struct buffer_head *bh)
 {
        struct buffer_head *evictee = NULL;
-       struct bh_lru *lru;
 
        check_irqs_on();
        bh_lru_lock();
-       lru = &__get_cpu_var(bh_lrus);
-       if (lru->bhs[0] != bh) {
+       if (__this_cpu_read(bh_lrus.bhs[0]) != bh) {
                struct buffer_head *bhs[BH_LRU_SIZE];
                int in;
                int out = 0;
@@ -1283,7 +1281,8 @@ static void bh_lru_install(struct buffer_head *bh)
                get_bh(bh);
                bhs[out++] = bh;
                for (in = 0; in < BH_LRU_SIZE; in++) {
-                       struct buffer_head *bh2 = lru->bhs[in];
+                       struct buffer_head *bh2 =
+                               __this_cpu_read(bh_lrus.bhs[in]);
 
                        if (bh2 == bh) {
                                __brelse(bh2);
@@ -1298,7 +1297,7 @@ static void bh_lru_install(struct buffer_head *bh)
                }
                while (out < BH_LRU_SIZE)
                        bhs[out++] = NULL;
-               memcpy(lru->bhs, bhs, sizeof(bhs));
+               memcpy(__this_cpu_ptr(&bh_lrus.bhs), bhs, sizeof(bhs));
        }
        bh_lru_unlock();
 
@@ -1313,23 +1312,22 @@ static struct buffer_head *
 lookup_bh_lru(struct block_device *bdev, sector_t block, unsigned size)
 {
        struct buffer_head *ret = NULL;
-       struct bh_lru *lru;
        unsigned int i;
 
        check_irqs_on();
        bh_lru_lock();
-       lru = &__get_cpu_var(bh_lrus);
        for (i = 0; i < BH_LRU_SIZE; i++) {
-               struct buffer_head *bh = lru->bhs[i];
+               struct buffer_head *bh = __this_cpu_read(bh_lrus.bhs[i]);
 
                if (bh && bh->b_bdev == bdev &&
                                bh->b_blocknr == block && bh->b_size == size) {
                        if (i) {
                                while (i) {
-                                       lru->bhs[i] = lru->bhs[i - 1];
+                                       __this_cpu_write(bh_lrus.bhs[i],
+                                               __this_cpu_read(bh_lrus.bhs[i - 1]));
                                        i--;
                                }
-                               lru->bhs[0] = bh;
+                               __this_cpu_write(bh_lrus.bhs[0], bh);
                        }
                        get_bh(bh);
                        ret = bh;
@@ -3203,22 +3201,23 @@ static void recalc_bh_state(void)
        int i;
        int tot = 0;
 
-       if (__get_cpu_var(bh_accounting).ratelimit++ < 4096)
+       if (__this_cpu_inc_return(bh_accounting.ratelimit) - 1 < 4096)
                return;
-       __get_cpu_var(bh_accounting).ratelimit = 0;
+       __this_cpu_write(bh_accounting.ratelimit, 0);
        for_each_online_cpu(i)
                tot += per_cpu(bh_accounting, i).nr;
        buffer_heads_over_limit = (tot > max_buffer_heads);
 }
-       
+
 struct buffer_head *alloc_buffer_head(gfp_t gfp_flags)
 {
        struct buffer_head *ret = kmem_cache_zalloc(bh_cachep, gfp_flags);
        if (ret) {
                INIT_LIST_HEAD(&ret->b_assoc_buffers);
-               get_cpu_var(bh_accounting).nr++;
+               preempt_disable();
+               __this_cpu_inc(bh_accounting.nr);
                recalc_bh_state();
-               put_cpu_var(bh_accounting);
+               preempt_enable();
        }
        return ret;
 }
@@ -3228,9 +3227,10 @@ void free_buffer_head(struct buffer_head *bh)
 {
        BUG_ON(!list_empty(&bh->b_assoc_buffers));
        kmem_cache_free(bh_cachep, bh);
-       get_cpu_var(bh_accounting).nr--;
+       preempt_disable();
+       __this_cpu_dec(bh_accounting.nr);
        recalc_bh_state();
-       put_cpu_var(bh_accounting);
+       preempt_enable();
 }
 EXPORT_SYMBOL(free_buffer_head);
 
@@ -3243,9 +3243,8 @@ static void buffer_exit_cpu(int cpu)
                brelse(b->bhs[i]);
                b->bhs[i] = NULL;
        }
-       get_cpu_var(bh_accounting).nr += per_cpu(bh_accounting, cpu).nr;
+       this_cpu_add(bh_accounting.nr, per_cpu(bh_accounting, cpu).nr);
        per_cpu(bh_accounting, cpu).nr = 0;
-       put_cpu_var(bh_accounting);
 }
 
 static int buffer_cpu_notify(struct notifier_block *self,
index 224d7bbd1fcc95d3dfadfc09e6d773d425eba95f..e654dfd092c3a8d0333af9771156898d1c9ed65e 100644 (file)
@@ -64,7 +64,9 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data,
                                   void *buffer, uint16_t maxbuf)
 {
        const struct TCP_Server_Info *server = cookie_netfs_data;
-       const struct sockaddr *sa = (struct sockaddr *) &server->addr.sockAddr;
+       const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr;
+       const struct sockaddr_in *addr = (struct sockaddr_in *) sa;
+       const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa;
        struct cifs_server_key *key = buffer;
        uint16_t key_len = sizeof(struct cifs_server_key);
 
@@ -76,16 +78,16 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data,
         */
        switch (sa->sa_family) {
        case AF_INET:
-               key->family = server->addr.sockAddr.sin_family;
-               key->port = server->addr.sockAddr.sin_port;
-               key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr;
+               key->family = sa->sa_family;
+               key->port = addr->sin_port;
+               key->addr[0].ipv4_addr = addr->sin_addr;
                key_len += sizeof(key->addr[0].ipv4_addr);
                break;
 
        case AF_INET6:
-               key->family = server->addr.sockAddr6.sin6_family;
-               key->port = server->addr.sockAddr6.sin6_port;
-               key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr;
+               key->family = sa->sa_family;
+               key->port = addr6->sin6_port;
+               key->addr[0].ipv6_addr = addr6->sin6_addr;
                key_len += sizeof(key->addr[0].ipv6_addr);
                break;
 
index 103ab8b605b004ea07ff4849bf1c1c51ce84b206..ede98300a8cdb53ac362c69a8c3dd6743f748343 100644 (file)
@@ -119,29 +119,27 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                    "Display Internal CIFS Data Structures for Debugging\n"
                    "---------------------------------------------------\n");
        seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
-       seq_printf(m, "Features: ");
+       seq_printf(m, "Features:");
 #ifdef CONFIG_CIFS_DFS_UPCALL
-       seq_printf(m, "dfs");
-       seq_putc(m, ' ');
+       seq_printf(m, " dfs");
 #endif
 #ifdef CONFIG_CIFS_FSCACHE
-       seq_printf(m, "fscache");
-       seq_putc(m, ' ');
+       seq_printf(m, " fscache");
 #endif
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
-       seq_printf(m, "lanman");
-       seq_putc(m, ' ');
+       seq_printf(m, " lanman");
 #endif
 #ifdef CONFIG_CIFS_POSIX
-       seq_printf(m, "posix");
-       seq_putc(m, ' ');
+       seq_printf(m, " posix");
 #endif
 #ifdef CONFIG_CIFS_UPCALL
-       seq_printf(m, "spnego");
-       seq_putc(m, ' ');
+       seq_printf(m, " spnego");
 #endif
 #ifdef CONFIG_CIFS_XATTR
-       seq_printf(m, "xattr");
+       seq_printf(m, " xattr");
+#endif
+#ifdef CONFIG_CIFS_ACL
+       seq_printf(m, " acl");
 #endif
        seq_putc(m, '\n');
        seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
index 87044906cd1fafeb37541588d6d31d96c55e147e..4dfba82831654910b3aab62a9803dc95855a52f1 100644 (file)
@@ -98,6 +98,8 @@ struct key *
 cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
 {
        struct TCP_Server_Info *server = sesInfo->server;
+       struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
+       struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
        char *description, *dp;
        size_t desc_len;
        struct key *spnego_key;
@@ -127,10 +129,10 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
        dp = description + strlen(description);
 
        /* add the server address */
-       if (server->addr.sockAddr.sin_family == AF_INET)
-               sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr);
-       else if (server->addr.sockAddr.sin_family == AF_INET6)
-               sprintf(dp, "ip6=%pI6", &server->addr.sockAddr6.sin6_addr);
+       if (server->dstaddr.ss_family == AF_INET)
+               sprintf(dp, "ip4=%pI4", &sa->sin_addr);
+       else if (server->dstaddr.ss_family == AF_INET6)
+               sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
        else
                goto out;
 
index f856732161aba416234842ed8d5a496df6336823..66f3d50d067682aa2203e30676550cce6421ec3a 100644 (file)
@@ -72,6 +72,7 @@ static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
        return 0;
 }
 
+/* must be called with server->srv_mutex held */
 int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
                  __u32 *pexpected_response_sequence_number)
 {
@@ -84,14 +85,12 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
        if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
                return rc;
 
-       spin_lock(&GlobalMid_Lock);
        cifs_pdu->Signature.Sequence.SequenceNumber =
                        cpu_to_le32(server->sequence_number);
        cifs_pdu->Signature.Sequence.Reserved = 0;
 
        *pexpected_response_sequence_number = server->sequence_number++;
        server->sequence_number++;
-       spin_unlock(&GlobalMid_Lock);
 
        rc = cifs_calculate_signature(cifs_pdu, server, smb_signature);
        if (rc)
@@ -149,6 +148,7 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
        return rc;
 }
 
+/* must be called with server->srv_mutex held */
 int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
                   __u32 *pexpected_response_sequence_number)
 {
@@ -162,14 +162,12 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
        if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
                return rc;
 
-       spin_lock(&GlobalMid_Lock);
        cifs_pdu->Signature.Sequence.SequenceNumber =
                                cpu_to_le32(server->sequence_number);
        cifs_pdu->Signature.Sequence.Reserved = 0;
 
        *pexpected_response_sequence_number = server->sequence_number++;
        server->sequence_number++;
-       spin_unlock(&GlobalMid_Lock);
 
        rc = cifs_calc_signature2(iov, n_vec, server, smb_signature);
        if (rc)
index 8e21e0fe65d5d663209ea114f57978b880104e49..5e7075d5f13970876879fdfe276e9f69e60b0a77 100644 (file)
@@ -329,6 +329,8 @@ cifs_alloc_inode(struct super_block *sb)
        cifs_inode->invalid_mapping = false;
        cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
        cifs_inode->server_eof = 0;
+       cifs_inode->uniqueid = 0;
+       cifs_inode->createtime = 0;
 
        /* Can not set i_flags here - they get immediately overwritten
           to zero by the VFS */
@@ -361,18 +363,19 @@ cifs_evict_inode(struct inode *inode)
 static void
 cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
 {
+       struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
+       struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
+
        seq_printf(s, ",addr=");
 
-       switch (server->addr.sockAddr.sin_family) {
+       switch (server->dstaddr.ss_family) {
        case AF_INET:
-               seq_printf(s, "%pI4", &server->addr.sockAddr.sin_addr.s_addr);
+               seq_printf(s, "%pI4", &sa->sin_addr.s_addr);
                break;
        case AF_INET6:
-               seq_printf(s, "%pI6",
-                          &server->addr.sockAddr6.sin6_addr.s6_addr);
-               if (server->addr.sockAddr6.sin6_scope_id)
-                       seq_printf(s, "%%%u",
-                                  server->addr.sockAddr6.sin6_scope_id);
+               seq_printf(s, "%pI6", &sa6->sin6_addr.s6_addr);
+               if (sa6->sin6_scope_id)
+                       seq_printf(s, "%%%u", sa6->sin6_scope_id);
                break;
        default:
                seq_printf(s, "(unknown)");
index 7136c0c3e2f961ec2c57d882163a1ffbc0e50ef1..606ca8bb710245484d32b3ec91415d2901812da4 100644 (file)
@@ -163,10 +163,7 @@ struct TCP_Server_Info {
        char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
        char *hostname; /* hostname portion of UNC string */
        struct socket *ssocket;
-       union {
-               struct sockaddr_in sockAddr;
-               struct sockaddr_in6 sockAddr6;
-       } addr;
+       struct sockaddr_storage dstaddr;
        struct sockaddr_storage srcaddr; /* locally bind to this IP */
        wait_queue_head_t response_q;
        wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
@@ -210,7 +207,7 @@ struct TCP_Server_Info {
        char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
        /* 16th byte of RFC1001 workstation name is always null */
        char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
-       __u32 sequence_number; /* needed for CIFS PDU signature */
+       __u32 sequence_number; /* for signing, protected by srv_mutex */
        struct session_key session_key;
        unsigned long lstrp; /* when we got last response from this server */
        u16 dialect; /* dialect index that server chose */
@@ -456,6 +453,7 @@ struct cifsInodeInfo {
        bool invalid_mapping:1;         /* pagecache is invalid */
        u64  server_eof;                /* current file size on server */
        u64  uniqueid;                  /* server inode number */
+       u64  createtime;                /* creation time on server */
 #ifdef CONFIG_CIFS_FSCACHE
        struct fscache_cookie *fscache;
 #endif
@@ -576,6 +574,7 @@ struct cifs_fattr {
        u64             cf_uniqueid;
        u64             cf_eof;
        u64             cf_bytes;
+       u64             cf_createtime;
        uid_t           cf_uid;
        gid_t           cf_gid;
        umode_t         cf_mode;
index 67acfb3acad271a51be1a1446d4f9828119e6b39..2f6795e524d3f39c34c2a1dbed77e11149f9330c 100644 (file)
@@ -401,15 +401,12 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
                cFYI(1, "Kerberos only mechanism, enable extended security");
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       }
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-       else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
+       } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
        else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
                cFYI(1, "NTLMSSP only mechanism, enable extended security");
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
        }
-#endif
 
        count = 0;
        for (i = 0; i < CIFS_NUM_PROT; i++) {
index cc1a8604a790b46767e066a59ef897f314144163..a65d311d163a4909f902b92d24e8f031830852eb 100644 (file)
@@ -64,8 +64,8 @@ struct smb_vol {
        char *UNC;
        char *UNCip;
        char *iocharset;  /* local code page for mapping to and from Unicode */
-       char source_rfc1001_name[16]; /* netbios name of client */
-       char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
+       char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
+       char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
        uid_t cred_uid;
        uid_t linux_uid;
        gid_t linux_gid;
@@ -115,8 +115,8 @@ struct smb_vol {
 #define TLINK_ERROR_EXPIRE     (1 * HZ)
 #define TLINK_IDLE_EXPIRE      (600 * HZ)
 
-static int ipv4_connect(struct TCP_Server_Info *server);
-static int ipv6_connect(struct TCP_Server_Info *server);
+static int ip_connect(struct TCP_Server_Info *server);
+static int generic_ip_connect(struct TCP_Server_Info *server);
 static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
 static void cifs_prune_tlinks(struct work_struct *work);
 
@@ -200,10 +200,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
        while ((server->tcpStatus != CifsExiting) &&
               (server->tcpStatus != CifsGood)) {
                try_to_freeze();
-               if (server->addr.sockAddr6.sin6_family == AF_INET6)
-                       rc = ipv6_connect(server);
-               else
-                       rc = ipv4_connect(server);
+
+               /* we should try only the port we connected to before */
+               rc = generic_ip_connect(server);
                if (rc) {
                        cFYI(1, "reconnect error %d", rc);
                        msleep(3000);
@@ -477,7 +476,7 @@ incomplete_rcv:
                         * initialize frame)
                         */
                        cifs_set_port((struct sockaddr *)
-                                       &server->addr.sockAddr, CIFS_PORT);
+                                       &server->dstaddr, CIFS_PORT);
                        cifs_reconnect(server);
                        csocket = server->ssocket;
                        wake_up(&server->response_q);
@@ -817,11 +816,11 @@ cifs_parse_mount_options(char *options, const char *devname,
         * informational, only used for servers that do not support
         * port 445 and it can be overridden at mount time
         */
-       memset(vol->source_rfc1001_name, 0x20, 15);
-       for (i = 0; i < strnlen(nodename, 15); i++)
+       memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN);
+       for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++)
                vol->source_rfc1001_name[i] = toupper(nodename[i]);
 
-       vol->source_rfc1001_name[15] = 0;
+       vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0;
        /* null target name indicates to use *SMBSERVR default called name
           if we end up sending RFC1001 session initialize */
        vol->target_rfc1001_name[0] = 0;
@@ -985,13 +984,11 @@ cifs_parse_mount_options(char *options, const char *devname,
                                return 1;
                        } else if (strnicmp(value, "krb5", 4) == 0) {
                                vol->secFlg |= CIFSSEC_MAY_KRB5;
-#ifdef CONFIG_CIFS_EXPERIMENTAL
                        } else if (strnicmp(value, "ntlmsspi", 8) == 0) {
                                vol->secFlg |= CIFSSEC_MAY_NTLMSSP |
                                        CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "ntlmssp", 7) == 0) {
                                vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
-#endif
                        } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
                                vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
                                        CIFSSEC_MUST_SIGN;
@@ -1168,22 +1165,22 @@ cifs_parse_mount_options(char *options, const char *devname,
                        if (!value || !*value || (*value == ' ')) {
                                cFYI(1, "invalid (empty) netbiosname");
                        } else {
-                               memset(vol->source_rfc1001_name, 0x20, 15);
-                               for (i = 0; i < 15; i++) {
-                               /* BB are there cases in which a comma can be
-                               valid in this workstation netbios name (and need
-                               special handling)? */
-
-                               /* We do not uppercase netbiosname for user */
+                               memset(vol->source_rfc1001_name, 0x20,
+                                       RFC1001_NAME_LEN);
+                               /*
+                                * FIXME: are there cases in which a comma can
+                                * be valid in workstation netbios name (and
+                                * need special handling)?
+                                */
+                               for (i = 0; i < RFC1001_NAME_LEN; i++) {
+                                       /* don't ucase netbiosname for user */
                                        if (value[i] == 0)
                                                break;
-                                       else
-                                               vol->source_rfc1001_name[i] =
-                                                               value[i];
+                                       vol->source_rfc1001_name[i] = value[i];
                                }
                                /* The string has 16th byte zero still from
                                set at top of the function  */
-                               if ((i == 15) && (value[i] != 0))
+                               if (i == RFC1001_NAME_LEN && value[i] != 0)
                                        printk(KERN_WARNING "CIFS: netbiosname"
                                                " longer than 15 truncated.\n");
                        }
@@ -1193,7 +1190,8 @@ cifs_parse_mount_options(char *options, const char *devname,
                                cFYI(1, "empty server netbiosname specified");
                        } else {
                                /* last byte, type, is 0x20 for servr type */
-                               memset(vol->target_rfc1001_name, 0x20, 16);
+                               memset(vol->target_rfc1001_name, 0x20,
+                                       RFC1001_NAME_LEN_WITH_NULL);
 
                                for (i = 0; i < 15; i++) {
                                /* BB are there cases in which a comma can be
@@ -1210,7 +1208,7 @@ cifs_parse_mount_options(char *options, const char *devname,
                                }
                                /* The string has 16th byte zero still from
                                   set at top of the function  */
-                               if ((i == 15) && (value[i] != 0))
+                               if (i == RFC1001_NAME_LEN && value[i] != 0)
                                        printk(KERN_WARNING "CIFS: server net"
                                        "biosname longer than 15 truncated.\n");
                        }
@@ -1341,10 +1339,8 @@ cifs_parse_mount_options(char *options, const char *devname,
                        vol->no_psx_acl = 0;
                } else if (strnicmp(data, "noacl", 5) == 0) {
                        vol->no_psx_acl = 1;
-#ifdef CONFIG_CIFS_EXPERIMENTAL
                } else if (strnicmp(data, "locallease", 6) == 0) {
                        vol->local_lease = 1;
-#endif
                } else if (strnicmp(data, "sign", 4) == 0) {
                        vol->secFlg |= CIFSSEC_MUST_SIGN;
                } else if (strnicmp(data, "seal", 4) == 0) {
@@ -1454,35 +1450,71 @@ srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs)
        }
 }
 
+/*
+ * If no port is specified in addr structure, we try to match with 445 port
+ * and if it fails - with 139 ports. It should be called only if address
+ * families of server and addr are equal.
+ */
+static bool
+match_port(struct TCP_Server_Info *server, struct sockaddr *addr)
+{
+       unsigned short int port, *sport;
+
+       switch (addr->sa_family) {
+       case AF_INET:
+               sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port;
+               port = ((struct sockaddr_in *) addr)->sin_port;
+               break;
+       case AF_INET6:
+               sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port;
+               port = ((struct sockaddr_in6 *) addr)->sin6_port;
+               break;
+       default:
+               WARN_ON(1);
+               return false;
+       }
+
+       if (!port) {
+               port = htons(CIFS_PORT);
+               if (port == *sport)
+                       return true;
+
+               port = htons(RFC1001_PORT);
+       }
+
+       return port == *sport;
+}
 
 static bool
 match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
              struct sockaddr *srcaddr)
 {
-       struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
-       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
-
        switch (addr->sa_family) {
-       case AF_INET:
-               if (addr4->sin_addr.s_addr !=
-                   server->addr.sockAddr.sin_addr.s_addr)
-                       return false;
-               if (addr4->sin_port &&
-                   addr4->sin_port != server->addr.sockAddr.sin_port)
+       case AF_INET: {
+               struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
+               struct sockaddr_in *srv_addr4 =
+                                       (struct sockaddr_in *)&server->dstaddr;
+
+               if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr)
                        return false;
                break;
-       case AF_INET6:
+       }
+       case AF_INET6: {
+               struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
+               struct sockaddr_in6 *srv_addr6 =
+                                       (struct sockaddr_in6 *)&server->dstaddr;
+
                if (!ipv6_addr_equal(&addr6->sin6_addr,
-                                    &server->addr.sockAddr6.sin6_addr))
+                                    &srv_addr6->sin6_addr))
                        return false;
-               if (addr6->sin6_scope_id !=
-                   server->addr.sockAddr6.sin6_scope_id)
-                       return false;
-               if (addr6->sin6_port &&
-                   addr6->sin6_port != server->addr.sockAddr6.sin6_port)
+               if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id)
                        return false;
                break;
        }
+       default:
+               WARN_ON(1);
+               return false; /* don't expect to be here */
+       }
 
        if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr))
                return false;
@@ -1549,6 +1581,9 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
                                   (struct sockaddr *)&vol->srcaddr))
                        continue;
 
+               if (!match_port(server, addr))
+                       continue;
+
                if (!match_security(server, vol))
                        continue;
 
@@ -1681,14 +1716,13 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
                cFYI(1, "attempting ipv6 connect");
                /* BB should we allow ipv6 on port 139? */
                /* other OS never observed in Wild doing 139 with v6 */
-               memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
-                       sizeof(struct sockaddr_in6));
-               rc = ipv6_connect(tcp_ses);
-       } else {
-               memcpy(&tcp_ses->addr.sockAddr, sin_server,
-                       sizeof(struct sockaddr_in));
-               rc = ipv4_connect(tcp_ses);
-       }
+               memcpy(&tcp_ses->dstaddr, sin_server6,
+                      sizeof(struct sockaddr_in6));
+       } else
+               memcpy(&tcp_ses->dstaddr, sin_server,
+                      sizeof(struct sockaddr_in));
+
+       rc = ip_connect(tcp_ses);
        if (rc < 0) {
                cERROR(1, "Error connecting to socket. Aborting operation");
                goto out_err_crypto_release;
@@ -1793,6 +1827,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 {
        int rc = -ENOMEM, xid;
        struct cifsSesInfo *ses;
+       struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
+       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
 
        xid = GetXid();
 
@@ -1836,12 +1872,10 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 
        /* new SMB session uses our server ref */
        ses->server = server;
-       if (server->addr.sockAddr6.sin6_family == AF_INET6)
-               sprintf(ses->serverName, "%pI6",
-                       &server->addr.sockAddr6.sin6_addr);
+       if (server->dstaddr.ss_family == AF_INET6)
+               sprintf(ses->serverName, "%pI6", &addr6->sin6_addr);
        else
-               sprintf(ses->serverName, "%pI4",
-                       &server->addr.sockAddr.sin_addr.s_addr);
+               sprintf(ses->serverName, "%pI4", &addr->sin_addr);
 
        if (volume_info->username)
                strncpy(ses->userName, volume_info->username,
@@ -2136,19 +2170,106 @@ bind_socket(struct TCP_Server_Info *server)
 }
 
 static int
-ipv4_connect(struct TCP_Server_Info *server)
+ip_rfc1001_connect(struct TCP_Server_Info *server)
+{
+       int rc = 0;
+       /*
+        * some servers require RFC1001 sessinit before sending
+        * negprot - BB check reconnection in case where second
+        * sessinit is sent but no second negprot
+        */
+       struct rfc1002_session_packet *ses_init_buf;
+       struct smb_hdr *smb_buf;
+       ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
+                              GFP_KERNEL);
+       if (ses_init_buf) {
+               ses_init_buf->trailer.session_req.called_len = 32;
+
+               if (server->server_RFC1001_name &&
+                   server->server_RFC1001_name[0] != 0)
+                       rfc1002mangle(ses_init_buf->trailer.
+                                     session_req.called_name,
+                                     server->server_RFC1001_name,
+                                     RFC1001_NAME_LEN_WITH_NULL);
+               else
+                       rfc1002mangle(ses_init_buf->trailer.
+                                     session_req.called_name,
+                                     DEFAULT_CIFS_CALLED_NAME,
+                                     RFC1001_NAME_LEN_WITH_NULL);
+
+               ses_init_buf->trailer.session_req.calling_len = 32;
+
+               /*
+                * calling name ends in null (byte 16) from old smb
+                * convention.
+                */
+               if (server->workstation_RFC1001_name &&
+                   server->workstation_RFC1001_name[0] != 0)
+                       rfc1002mangle(ses_init_buf->trailer.
+                                     session_req.calling_name,
+                                     server->workstation_RFC1001_name,
+                                     RFC1001_NAME_LEN_WITH_NULL);
+               else
+                       rfc1002mangle(ses_init_buf->trailer.
+                                     session_req.calling_name,
+                                     "LINUX_CIFS_CLNT",
+                                     RFC1001_NAME_LEN_WITH_NULL);
+
+               ses_init_buf->trailer.session_req.scope1 = 0;
+               ses_init_buf->trailer.session_req.scope2 = 0;
+               smb_buf = (struct smb_hdr *)ses_init_buf;
+
+               /* sizeof RFC1002_SESSION_REQUEST with no scope */
+               smb_buf->smb_buf_length = 0x81000044;
+               rc = smb_send(server, smb_buf, 0x44);
+               kfree(ses_init_buf);
+               /*
+                * RFC1001 layer in at least one server
+                * requires very short break before negprot
+                * presumably because not expecting negprot
+                * to follow so fast.  This is a simple
+                * solution that works without
+                * complicating the code and causes no
+                * significant slowing down on mount
+                * for everyone else
+                */
+               usleep_range(1000, 2000);
+       }
+       /*
+        * else the negprot may still work without this
+        * even though malloc failed
+        */
+
+       return rc;
+}
+
+static int
+generic_ip_connect(struct TCP_Server_Info *server)
 {
        int rc = 0;
-       int val;
-       bool connected = false;
-       __be16 orig_port = 0;
+       unsigned short int sport;
+       int slen, sfamily;
        struct socket *socket = server->ssocket;
+       struct sockaddr *saddr;
+
+       saddr = (struct sockaddr *) &server->dstaddr;
+
+       if (server->dstaddr.ss_family == AF_INET6) {
+               sport = ((struct sockaddr_in6 *) saddr)->sin6_port;
+               slen = sizeof(struct sockaddr_in6);
+               sfamily = AF_INET6;
+       } else {
+               sport = ((struct sockaddr_in *) saddr)->sin_port;
+               slen = sizeof(struct sockaddr_in);
+               sfamily = AF_INET;
+       }
 
        if (socket == NULL) {
-               rc = sock_create_kern(PF_INET, SOCK_STREAM,
+               rc = sock_create_kern(sfamily, SOCK_STREAM,
                                      IPPROTO_TCP, &socket);
                if (rc < 0) {
                        cERROR(1, "Error %d creating socket", rc);
+                       server->ssocket = NULL;
                        return rc;
                }
 
@@ -2156,63 +2277,28 @@ ipv4_connect(struct TCP_Server_Info *server)
                cFYI(1, "Socket created");
                server->ssocket = socket;
                socket->sk->sk_allocation = GFP_NOFS;
-               cifs_reclassify_socket4(socket);
+               if (sfamily == AF_INET6)
+                       cifs_reclassify_socket6(socket);
+               else
+                       cifs_reclassify_socket4(socket);
        }
 
        rc = bind_socket(server);
        if (rc < 0)
                return rc;
 
-       /* user overrode default port */
-       if (server->addr.sockAddr.sin_port) {
-               rc = socket->ops->connect(socket, (struct sockaddr *)
-                                         &server->addr.sockAddr,
-                                         sizeof(struct sockaddr_in), 0);
-               if (rc >= 0)
-                       connected = true;
-       }
-
-       if (!connected) {
-               /* save original port so we can retry user specified port
-                       later if fall back ports fail this time  */
-               orig_port = server->addr.sockAddr.sin_port;
-
-               /* do not retry on the same port we just failed on */
-               if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
-                       server->addr.sockAddr.sin_port = htons(CIFS_PORT);
-                       rc = socket->ops->connect(socket,
-                                               (struct sockaddr *)
-                                               &server->addr.sockAddr,
-                                               sizeof(struct sockaddr_in), 0);
-                       if (rc >= 0)
-                               connected = true;
-               }
-       }
-       if (!connected) {
-               server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
-               rc = socket->ops->connect(socket, (struct sockaddr *)
-                                             &server->addr.sockAddr,
-                                             sizeof(struct sockaddr_in), 0);
-               if (rc >= 0)
-                       connected = true;
-       }
-
-       /* give up here - unless we want to retry on different
-               protocol families some day */
-       if (!connected) {
-               if (orig_port)
-                       server->addr.sockAddr.sin_port = orig_port;
-               cFYI(1, "Error %d connecting to server via ipv4", rc);
+       rc = socket->ops->connect(socket, saddr, slen, 0);
+       if (rc < 0) {
+               cFYI(1, "Error %d connecting to server", rc);
                sock_release(socket);
                server->ssocket = NULL;
                return rc;
        }
 
-
        /*
         * Eventually check for other socket options to change from
-        *  the default. sock_setsockopt not used because it expects
-        *  user space buffer
+        * the default. sock_setsockopt not used because it expects
+        * user space buffer
         */
        socket->sk->sk_rcvtimeo = 7 * HZ;
        socket->sk->sk_sndtimeo = 5 * HZ;
@@ -2226,7 +2312,7 @@ ipv4_connect(struct TCP_Server_Info *server)
        }
 
        if (server->tcp_nodelay) {
-               val = 1;
+               int val = 1;
                rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY,
                                (char *)&val, sizeof(val));
                if (rc)
@@ -2237,161 +2323,39 @@ ipv4_connect(struct TCP_Server_Info *server)
                 socket->sk->sk_sndbuf,
                 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
 
-       /* send RFC1001 sessinit */
-       if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
-               /* some servers require RFC1001 sessinit before sending
-               negprot - BB check reconnection in case where second
-               sessinit is sent but no second negprot */
-               struct rfc1002_session_packet *ses_init_buf;
-               struct smb_hdr *smb_buf;
-               ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
-                                      GFP_KERNEL);
-               if (ses_init_buf) {
-                       ses_init_buf->trailer.session_req.called_len = 32;
-                       if (server->server_RFC1001_name &&
-                           server->server_RFC1001_name[0] != 0)
-                               rfc1002mangle(ses_init_buf->trailer.
-                                               session_req.called_name,
-                                             server->server_RFC1001_name,
-                                             RFC1001_NAME_LEN_WITH_NULL);
-                       else
-                               rfc1002mangle(ses_init_buf->trailer.
-                                               session_req.called_name,
-                                             DEFAULT_CIFS_CALLED_NAME,
-                                             RFC1001_NAME_LEN_WITH_NULL);
-
-                       ses_init_buf->trailer.session_req.calling_len = 32;
-
-                       /* calling name ends in null (byte 16) from old smb
-                       convention. */
-                       if (server->workstation_RFC1001_name &&
-                           server->workstation_RFC1001_name[0] != 0)
-                               rfc1002mangle(ses_init_buf->trailer.
-                                               session_req.calling_name,
-                                             server->workstation_RFC1001_name,
-                                             RFC1001_NAME_LEN_WITH_NULL);
-                       else
-                               rfc1002mangle(ses_init_buf->trailer.
-                                               session_req.calling_name,
-                                             "LINUX_CIFS_CLNT",
-                                             RFC1001_NAME_LEN_WITH_NULL);
-
-                       ses_init_buf->trailer.session_req.scope1 = 0;
-                       ses_init_buf->trailer.session_req.scope2 = 0;
-                       smb_buf = (struct smb_hdr *)ses_init_buf;
-                       /* sizeof RFC1002_SESSION_REQUEST with no scope */
-                       smb_buf->smb_buf_length = 0x81000044;
-                       rc = smb_send(server, smb_buf, 0x44);
-                       kfree(ses_init_buf);
-                       msleep(1); /* RFC1001 layer in at least one server
-                                     requires very short break before negprot
-                                     presumably because not expecting negprot
-                                     to follow so fast.  This is a simple
-                                     solution that works without
-                                     complicating the code and causes no
-                                     significant slowing down on mount
-                                     for everyone else */
-               }
-               /* else the negprot may still work without this
-               even though malloc failed */
-
-       }
+       if (sport == htons(RFC1001_PORT))
+               rc = ip_rfc1001_connect(server);
 
        return rc;
 }
 
 static int
-ipv6_connect(struct TCP_Server_Info *server)
+ip_connect(struct TCP_Server_Info *server)
 {
-       int rc = 0;
-       int val;
-       bool connected = false;
-       __be16 orig_port = 0;
-       struct socket *socket = server->ssocket;
+       unsigned short int *sport;
+       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
+       struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
 
-       if (socket == NULL) {
-               rc = sock_create_kern(PF_INET6, SOCK_STREAM,
-                                     IPPROTO_TCP, &socket);
-               if (rc < 0) {
-                       cERROR(1, "Error %d creating ipv6 socket", rc);
-                       socket = NULL;
-                       return rc;
-               }
+       if (server->dstaddr.ss_family == AF_INET6)
+               sport = &addr6->sin6_port;
+       else
+               sport = &addr->sin_port;
 
-               /* BB other socket options to set KEEPALIVE, NODELAY? */
-               cFYI(1, "ipv6 Socket created");
-               server->ssocket = socket;
-               socket->sk->sk_allocation = GFP_NOFS;
-               cifs_reclassify_socket6(socket);
-       }
+       if (*sport == 0) {
+               int rc;
 
-       rc = bind_socket(server);
-       if (rc < 0)
-               return rc;
+               /* try with 445 port at first */
+               *sport = htons(CIFS_PORT);
 
-       /* user overrode default port */
-       if (server->addr.sockAddr6.sin6_port) {
-               rc = socket->ops->connect(socket,
-                               (struct sockaddr *) &server->addr.sockAddr6,
-                               sizeof(struct sockaddr_in6), 0);
-               if (rc >= 0)
-                       connected = true;
-       }
-
-       if (!connected) {
-               /* save original port so we can retry user specified port
-                       later if fall back ports fail this time  */
-
-               orig_port = server->addr.sockAddr6.sin6_port;
-               /* do not retry on the same port we just failed on */
-               if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
-                       server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
-                       rc = socket->ops->connect(socket, (struct sockaddr *)
-                                       &server->addr.sockAddr6,
-                                       sizeof(struct sockaddr_in6), 0);
-                       if (rc >= 0)
-                               connected = true;
-               }
-       }
-       if (!connected) {
-               server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
-               rc = socket->ops->connect(socket, (struct sockaddr *)
-                               &server->addr.sockAddr6,
-                               sizeof(struct sockaddr_in6), 0);
+               rc = generic_ip_connect(server);
                if (rc >= 0)
-                       connected = true;
-       }
-
-       /* give up here - unless we want to retry on different
-               protocol families some day */
-       if (!connected) {
-               if (orig_port)
-                       server->addr.sockAddr6.sin6_port = orig_port;
-               cFYI(1, "Error %d connecting to server via ipv6", rc);
-               sock_release(socket);
-               server->ssocket = NULL;
-               return rc;
-       }
-
-       /*
-        * Eventually check for other socket options to change from
-        * the default. sock_setsockopt not used because it expects
-        * user space buffer
-        */
-       socket->sk->sk_rcvtimeo = 7 * HZ;
-       socket->sk->sk_sndtimeo = 5 * HZ;
+                       return rc;
 
-       if (server->tcp_nodelay) {
-               val = 1;
-               rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY,
-                               (char *)&val, sizeof(val));
-               if (rc)
-                       cFYI(1, "set TCP_NODELAY socket option error %d", rc);
+               /* if it failed, try with 139 port */
+               *sport = htons(RFC1001_PORT);
        }
 
-       server->ssocket = socket;
-
-       return rc;
+       return generic_ip_connect(server);
 }
 
 void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
index db2a58c00f7b237f8e8cd02147ecf97cbf8cbca5..2e773825835e837a4fd77ff038928c29dce191aa 100644 (file)
@@ -293,10 +293,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                        args.uid = NO_CHANGE_64;
                        args.gid = NO_CHANGE_64;
                }
-               CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
-                                       cifs_sb->local_nls,
-                                       cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+               CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle,
+                                       current->tgid);
        } else {
                /* BB implement mode setting via Windows security
                   descriptors e.g. */
index 5a28660ca2b5e619955c05d74d9d84b95a994a4b..d843631c028d5939f57992701e95943318fe14ab 100644 (file)
@@ -104,53 +104,6 @@ static inline int cifs_get_disposition(unsigned int flags)
                return FILE_OPEN;
 }
 
-static inline int cifs_open_inode_helper(struct inode *inode,
-       struct cifsTconInfo *pTcon, __u32 oplock, FILE_ALL_INFO *buf,
-       char *full_path, int xid)
-{
-       struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
-       struct timespec temp;
-       int rc;
-
-       if (pCifsInode->clientCanCacheRead) {
-               /* we have the inode open somewhere else
-                  no need to discard cache data */
-               goto client_can_cache;
-       }
-
-       /* BB need same check in cifs_create too? */
-       /* if not oplocked, invalidate inode pages if mtime or file
-          size changed */
-       temp = cifs_NTtimeToUnix(buf->LastWriteTime);
-       if (timespec_equal(&inode->i_mtime, &temp) &&
-                          (inode->i_size ==
-                           (loff_t)le64_to_cpu(buf->EndOfFile))) {
-               cFYI(1, "inode unchanged on server");
-       } else {
-               if (inode->i_mapping) {
-                       /* BB no need to lock inode until after invalidate
-                       since namei code should already have it locked? */
-                       rc = filemap_write_and_wait(inode->i_mapping);
-                       mapping_set_error(inode->i_mapping, rc);
-               }
-               cFYI(1, "invalidating remote inode since open detected it "
-                        "changed");
-               invalidate_remote_inode(inode);
-       }
-
-client_can_cache:
-       if (pTcon->unix_ext)
-               rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
-                                             xid);
-       else
-               rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
-                                        xid, NULL);
-
-       cifs_set_oplock_level(pCifsInode, oplock);
-
-       return rc;
-}
-
 int cifs_posix_open(char *full_path, struct inode **pinode,
                        struct super_block *sb, int mode, unsigned int f_flags,
                        __u32 *poplock, __u16 *pnetfid, int xid)
@@ -213,6 +166,76 @@ posix_open_ret:
        return rc;
 }
 
+static int
+cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
+            struct cifsTconInfo *tcon, unsigned int f_flags, __u32 *poplock,
+            __u16 *pnetfid, int xid)
+{
+       int rc;
+       int desiredAccess;
+       int disposition;
+       FILE_ALL_INFO *buf;
+
+       desiredAccess = cifs_convert_flags(f_flags);
+
+/*********************************************************************
+ *  open flag mapping table:
+ *
+ *     POSIX Flag            CIFS Disposition
+ *     ----------            ----------------
+ *     O_CREAT               FILE_OPEN_IF
+ *     O_CREAT | O_EXCL      FILE_CREATE
+ *     O_CREAT | O_TRUNC     FILE_OVERWRITE_IF
+ *     O_TRUNC               FILE_OVERWRITE
+ *     none of the above     FILE_OPEN
+ *
+ *     Note that there is not a direct match between disposition
+ *     FILE_SUPERSEDE (ie create whether or not file exists although
+ *     O_CREAT | O_TRUNC is similar but truncates the existing
+ *     file rather than creating a new file as FILE_SUPERSEDE does
+ *     (which uses the attributes / metadata passed in on open call)
+ *?
+ *?  O_SYNC is a reasonable match to CIFS writethrough flag
+ *?  and the read write flags match reasonably.  O_LARGEFILE
+ *?  is irrelevant because largefile support is always used
+ *?  by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
+ *      O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
+ *********************************************************************/
+
+       disposition = cifs_get_disposition(f_flags);
+
+       /* BB pass O_SYNC flag through on file attributes .. BB */
+
+       buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       if (tcon->ses->capabilities & CAP_NT_SMBS)
+               rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
+                        desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
+                        cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+                                & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       else
+               rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
+                       desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
+                       cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+                               & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+       if (rc)
+               goto out;
+
+       if (tcon->unix_ext)
+               rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
+                                             xid);
+       else
+               rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
+                                        xid, pnetfid);
+
+out:
+       kfree(buf);
+       return rc;
+}
+
 struct cifsFileInfo *
 cifs_new_fileinfo(__u16 fileHandle, struct file *file,
                  struct tcon_link *tlink, __u32 oplock)
@@ -317,10 +340,8 @@ int cifs_open(struct inode *inode, struct file *file)
        struct cifsFileInfo *pCifsFile = NULL;
        struct cifsInodeInfo *pCifsInode;
        char *full_path = NULL;
-       int desiredAccess;
-       int disposition;
+       bool posix_open_ok = false;
        __u16 netfid;
-       FILE_ALL_INFO *buf = NULL;
 
        xid = GetXid();
 
@@ -358,17 +379,7 @@ int cifs_open(struct inode *inode, struct file *file)
                                file->f_flags, &oplock, &netfid, xid);
                if (rc == 0) {
                        cFYI(1, "posix open succeeded");
-
-                       pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
-                                                     oplock);
-                       if (pCifsFile == NULL) {
-                               CIFSSMBClose(xid, tcon, netfid);
-                               rc = -ENOMEM;
-                       }
-
-                       cifs_fscache_set_inode_cookie(inode, file);
-
-                       goto out;
+                       posix_open_ok = true;
                } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
                        if (tcon->ses->serverNOS)
                                cERROR(1, "server %s of type %s returned"
@@ -385,103 +396,39 @@ int cifs_open(struct inode *inode, struct file *file)
                   or DFS errors */
        }
 
-       desiredAccess = cifs_convert_flags(file->f_flags);
-
-/*********************************************************************
- *  open flag mapping table:
- *
- *     POSIX Flag            CIFS Disposition
- *     ----------            ----------------
- *     O_CREAT               FILE_OPEN_IF
- *     O_CREAT | O_EXCL      FILE_CREATE
- *     O_CREAT | O_TRUNC     FILE_OVERWRITE_IF
- *     O_TRUNC               FILE_OVERWRITE
- *     none of the above     FILE_OPEN
- *
- *     Note that there is not a direct match between disposition
- *     FILE_SUPERSEDE (ie create whether or not file exists although
- *     O_CREAT | O_TRUNC is similar but truncates the existing
- *     file rather than creating a new file as FILE_SUPERSEDE does
- *     (which uses the attributes / metadata passed in on open call)
- *?
- *?  O_SYNC is a reasonable match to CIFS writethrough flag
- *?  and the read write flags match reasonably.  O_LARGEFILE
- *?  is irrelevant because largefile support is always used
- *?  by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
- *      O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
- *********************************************************************/
-
-       disposition = cifs_get_disposition(file->f_flags);
-
-       /* BB pass O_SYNC flag through on file attributes .. BB */
-
-       /* Also refresh inode by passing in file_info buf returned by SMBOpen
-          and calling get_inode_info with returned buf (at least helps
-          non-Unix server case) */
-
-       /* BB we can not do this if this is the second open of a file
-          and the first handle has writebehind data, we might be
-          able to simply do a filemap_fdatawrite/filemap_fdatawait first */
-       buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
-       if (!buf) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       if (tcon->ses->capabilities & CAP_NT_SMBS)
-               rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
-                        desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
-                        cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
-                                & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       else
-               rc = -EIO; /* no NT SMB support fall into legacy open below */
-
-       if (rc == -EIO) {
-               /* Old server, try legacy style OpenX */
-               rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
-                       desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
-                       cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
-                               & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       }
-       if (rc) {
-               cFYI(1, "cifs_open returned 0x%x", rc);
-               goto out;
+       if (!posix_open_ok) {
+               rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
+                                 file->f_flags, &oplock, &netfid, xid);
+               if (rc)
+                       goto out;
        }
 
-       rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid);
-       if (rc != 0)
-               goto out;
-
        pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
        if (pCifsFile == NULL) {
+               CIFSSMBClose(xid, tcon, netfid);
                rc = -ENOMEM;
                goto out;
        }
 
        cifs_fscache_set_inode_cookie(inode, file);
 
-       if (oplock & CIFS_CREATE_ACTION) {
+       if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
                /* time to set mode which we can not set earlier due to
                   problems creating new read-only files */
-               if (tcon->unix_ext) {
-                       struct cifs_unix_set_info_args args = {
-                               .mode   = inode->i_mode,
-                               .uid    = NO_CHANGE_64,
-                               .gid    = NO_CHANGE_64,
-                               .ctime  = NO_CHANGE_64,
-                               .atime  = NO_CHANGE_64,
-                               .mtime  = NO_CHANGE_64,
-                               .device = 0,
-                       };
-                       CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
-                                              cifs_sb->local_nls,
-                                              cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
-               }
+               struct cifs_unix_set_info_args args = {
+                       .mode   = inode->i_mode,
+                       .uid    = NO_CHANGE_64,
+                       .gid    = NO_CHANGE_64,
+                       .ctime  = NO_CHANGE_64,
+                       .atime  = NO_CHANGE_64,
+                       .mtime  = NO_CHANGE_64,
+                       .device = 0,
+               };
+               CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
+                                       pCifsFile->pid);
        }
 
 out:
-       kfree(buf);
        kfree(full_path);
        FreeXid(xid);
        cifs_put_tlink(tlink);
index a853a89857a5d4fbe9a50590377bace07768e508..0c7e36910e3106846bfde09610045230a1b2e745 100644 (file)
@@ -518,6 +518,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
 
        fattr->cf_eof = le64_to_cpu(info->EndOfFile);
        fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
+       fattr->cf_createtime = le64_to_cpu(info->CreationTime);
 
        if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
                fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
@@ -779,6 +780,10 @@ cifs_find_inode(struct inode *inode, void *opaque)
        if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
                return 0;
 
+       /* use createtime like an i_generation field */
+       if (CIFS_I(inode)->createtime != fattr->cf_createtime)
+               return 0;
+
        /* don't match inode of different type */
        if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
                return 0;
@@ -796,6 +801,7 @@ cifs_init_inode(struct inode *inode, void *opaque)
        struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
 
        CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
+       CIFS_I(inode)->createtime = fattr->cf_createtime;
        return 0;
 }
 
index ec5b68e3b928d56ee5b36157c21e67902508f51a..76b1b37c9e6b7e916258cb19a862875843d20e66 100644 (file)
@@ -160,6 +160,7 @@ cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
        fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes);
        fattr->cf_eof = le64_to_cpu(info->EndOfFile);
        fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
+       fattr->cf_createtime = le64_to_cpu(info->CreationTime);
        fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
        fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
        fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
index 7b01d3f6eed6e76cff6317f16c43b366c1af595d..eb746486e49e8da35ee1b7d940e964f191fe9df9 100644 (file)
@@ -420,7 +420,6 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
        return 0;
 }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 /* BB Move to ntlmssp.c eventually */
 
 /* We do not malloc the blob, it is passed in pbuffer, because
@@ -431,13 +430,14 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
        NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer;
        __u32 flags;
 
+       memset(pbuffer, 0, sizeof(NEGOTIATE_MESSAGE));
        memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
        sec_blob->MessageType = NtLmNegotiate;
 
        /* BB is NTLMV2 session security format easier to use here? */
        flags = NTLMSSP_NEGOTIATE_56 |  NTLMSSP_REQUEST_TARGET |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
-               NTLMSSP_NEGOTIATE_NTLM;
+               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
        if (ses->server->secMode &
                        (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
                flags |= NTLMSSP_NEGOTIATE_SIGN;
@@ -446,7 +446,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
                                NTLMSSP_NEGOTIATE_EXTENDED_SEC;
        }
 
-       sec_blob->NegotiateFlags |= cpu_to_le32(flags);
+       sec_blob->NegotiateFlags = cpu_to_le32(flags);
 
        sec_blob->WorkstationName.BufferOffset = 0;
        sec_blob->WorkstationName.Length = 0;
@@ -477,7 +477,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
        flags = NTLMSSP_NEGOTIATE_56 |
                NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
-               NTLMSSP_NEGOTIATE_NTLM;
+               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
        if (ses->server->secMode &
           (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                flags |= NTLMSSP_NEGOTIATE_SIGN;
@@ -485,7 +485,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
                flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
 
        tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE);
-       sec_blob->NegotiateFlags |= cpu_to_le32(flags);
+       sec_blob->NegotiateFlags = cpu_to_le32(flags);
 
        sec_blob->LmChallengeResponse.BufferOffset =
                                cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE));
@@ -544,8 +544,9 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
        sec_blob->WorkstationName.MaximumLength = 0;
        tmp += 2;
 
-       if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
-                       !calc_seckey(ses)) {
+       if (((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) ||
+               (ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
+                       && !calc_seckey(ses)) {
                memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
                sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
                sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
@@ -563,17 +564,6 @@ setup_ntlmv2_ret:
        return rc;
 }
 
-
-static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB,
-                                struct cifsSesInfo *ses)
-{
-       build_ntlmssp_negotiate_blob(&pSMB->req.SecurityBlob[0], ses);
-       pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
-
-       return;
-}
-#endif
-
 int
 CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
               const struct nls_table *nls_cp)
@@ -814,71 +804,70 @@ ssetup_ntlmssp_authenticate:
                rc = -ENOSYS;
                goto ssetup_exit;
 #endif /* CONFIG_CIFS_UPCALL */
-       } else {
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-               if (type == RawNTLMSSP) {
-                       if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
-                               cERROR(1, "NTLMSSP requires Unicode support");
-                               rc = -ENOSYS;
+       } else if (type == RawNTLMSSP) {
+               if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
+                       cERROR(1, "NTLMSSP requires Unicode support");
+                       rc = -ENOSYS;
+                       goto ssetup_exit;
+               }
+
+               cFYI(1, "ntlmssp session setup phase %d", phase);
+               pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+               capabilities |= CAP_EXTENDED_SECURITY;
+               pSMB->req.Capabilities |= cpu_to_le32(capabilities);
+               switch(phase) {
+               case NtLmNegotiate:
+                       build_ntlmssp_negotiate_blob(
+                               pSMB->req.SecurityBlob, ses);
+                       iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
+                       iov[1].iov_base = pSMB->req.SecurityBlob;
+                       pSMB->req.SecurityBlobLength =
+                               cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
+                       break;
+               case NtLmAuthenticate:
+                       /*
+                        * 5 is an empirical value, large enough to hold
+                        * authenticate message plus max 10 of av paris,
+                        * domain, user, workstation names, flags, etc.
+                        */
+                       ntlmsspblob = kzalloc(
+                               5*sizeof(struct _AUTHENTICATE_MESSAGE),
+                               GFP_KERNEL);
+                       if (!ntlmsspblob) {
+                               cERROR(1, "Can't allocate NTLMSSP blob");
+                               rc = -ENOMEM;
                                goto ssetup_exit;
                        }
 
-                       cFYI(1, "ntlmssp session setup phase %d", phase);
-                       pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
-                       capabilities |= CAP_EXTENDED_SECURITY;
-                       pSMB->req.Capabilities |= cpu_to_le32(capabilities);
-                       if (phase == NtLmNegotiate) {
-                               setup_ntlmssp_neg_req(pSMB, ses);
-                               iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
-                               iov[1].iov_base = &pSMB->req.SecurityBlob[0];
-                       } else if (phase == NtLmAuthenticate) {
-                               /* 5 is an empirical value, large enought to
-                                * hold authenticate message, max 10 of
-                                * av paris, doamin,user,workstation mames,
-                                * flags etc..
-                                */
-                               ntlmsspblob = kmalloc(
-                                       5*sizeof(struct _AUTHENTICATE_MESSAGE),
-                                       GFP_KERNEL);
-                               if (!ntlmsspblob) {
-                                       cERROR(1, "Can't allocate NTLMSSP");
-                                       rc = -ENOMEM;
-                                       goto ssetup_exit;
-                               }
-
-                               rc = build_ntlmssp_auth_blob(ntlmsspblob,
-                                                       &blob_len, ses, nls_cp);
-                               if (rc)
-                                       goto ssetup_exit;
-                               iov[1].iov_len = blob_len;
-                               iov[1].iov_base = ntlmsspblob;
-                               pSMB->req.SecurityBlobLength =
-                                       cpu_to_le16(blob_len);
-                               /* Make sure that we tell the server that we
-                                  are using the uid that it just gave us back
-                                  on the response (challenge) */
-                               smb_buf->Uid = ses->Suid;
-                       } else {
-                               cERROR(1, "invalid phase %d", phase);
-                               rc = -ENOSYS;
+                       rc = build_ntlmssp_auth_blob(ntlmsspblob,
+                                               &blob_len, ses, nls_cp);
+                       if (rc)
                                goto ssetup_exit;
-                       }
-                       /* unicode strings must be word aligned */
-                       if ((iov[0].iov_len + iov[1].iov_len) % 2) {
-                               *bcc_ptr = 0;
-                               bcc_ptr++;
-                       }
-                       unicode_oslm_strings(&bcc_ptr, nls_cp);
-               } else {
-                       cERROR(1, "secType %d not supported!", type);
+                       iov[1].iov_len = blob_len;
+                       iov[1].iov_base = ntlmsspblob;
+                       pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
+                       /*
+                        * Make sure that we tell the server that we are using
+                        * the uid that it just gave us back on the response
+                        * (challenge)
+                        */
+                       smb_buf->Uid = ses->Suid;
+                       break;
+               default:
+                       cERROR(1, "invalid phase %d", phase);
                        rc = -ENOSYS;
                        goto ssetup_exit;
                }
-#else
+               /* unicode strings must be word aligned */
+               if ((iov[0].iov_len + iov[1].iov_len) % 2) {
+                       *bcc_ptr = 0;
+                       bcc_ptr++;
+               }
+               unicode_oslm_strings(&bcc_ptr, nls_cp);
+       } else {
                cERROR(1, "secType %d not supported!", type);
                rc = -ENOSYS;
                goto ssetup_exit;
-#endif
        }
 
        iov[2].iov_base = str_area;
index e0588cdf4cc5d5a1e8a73c1190c21f2d6cbe4986..59ca81b16919ea2a9d978ced67df60315499711c 100644 (file)
@@ -119,7 +119,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
        if (ssocket == NULL)
                return -ENOTSOCK; /* BB eventually add reconnect code here */
 
-       smb_msg.msg_name = (struct sockaddr *) &server->addr.sockAddr;
+       smb_msg.msg_name = (struct sockaddr *) &server->dstaddr;
        smb_msg.msg_namelen = sizeof(struct sockaddr);
        smb_msg.msg_control = NULL;
        smb_msg.msg_controllen = 0;
index 37a34c2c622a12525927956223dcb79c80d000a5..9c64ae9e4c1a9f6545552504e0b1184fc646a1ea 100644 (file)
@@ -63,6 +63,9 @@
 #define NEEDED_RMEM (4*1024*1024)
 #define CONN_HASH_SIZE 32
 
+/* Number of messages to send before rescheduling */
+#define MAX_SEND_MSG_COUNT 25
+
 struct cbuf {
        unsigned int base;
        unsigned int len;
@@ -108,6 +111,7 @@ struct connection {
 #define CF_INIT_PENDING 4
 #define CF_IS_OTHERCON 5
 #define CF_CLOSE 6
+#define CF_APP_LIMITED 7
        struct list_head writequeue;  /* List of outgoing writequeue_entries */
        spinlock_t writequeue_lock;
        int (*rx_action) (struct connection *); /* What to do when active */
@@ -295,7 +299,17 @@ static void lowcomms_write_space(struct sock *sk)
 {
        struct connection *con = sock2con(sk);
 
-       if (con && !test_and_set_bit(CF_WRITE_PENDING, &con->flags))
+       if (!con)
+               return;
+
+       clear_bit(SOCK_NOSPACE, &con->sock->flags);
+
+       if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) {
+               con->sock->sk->sk_write_pending--;
+               clear_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags);
+       }
+
+       if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
                queue_work(send_workqueue, &con->swork);
 }
 
@@ -915,6 +929,7 @@ static void tcp_connect_to_sock(struct connection *con)
        struct sockaddr_storage saddr, src_addr;
        int addr_len;
        struct socket *sock = NULL;
+       int one = 1;
 
        if (con->nodeid == 0) {
                log_print("attempt to connect sock 0 foiled");
@@ -960,6 +975,11 @@ static void tcp_connect_to_sock(struct connection *con)
        make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len);
 
        log_print("connecting to %d", con->nodeid);
+
+       /* Turn off Nagle's algorithm */
+       kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one,
+                         sizeof(one));
+
        result =
                sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
                                   O_NONBLOCK);
@@ -1011,6 +1031,10 @@ static struct socket *tcp_create_listen_sock(struct connection *con,
                goto create_out;
        }
 
+       /* Turn off Nagle's algorithm */
+       kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one,
+                         sizeof(one));
+
        result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                                   (char *)&one, sizeof(one));
 
@@ -1297,6 +1321,7 @@ static void send_to_sock(struct connection *con)
        const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
        struct writequeue_entry *e;
        int len, offset;
+       int count = 0;
 
        mutex_lock(&con->sock_mutex);
        if (con->sock == NULL)
@@ -1319,14 +1344,27 @@ static void send_to_sock(struct connection *con)
                        ret = kernel_sendpage(con->sock, e->page, offset, len,
                                              msg_flags);
                        if (ret == -EAGAIN || ret == 0) {
+                               if (ret == -EAGAIN &&
+                                   test_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags) &&
+                                   !test_and_set_bit(CF_APP_LIMITED, &con->flags)) {
+                                       /* Notify TCP that we're limited by the
+                                        * application window size.
+                                        */
+                                       set_bit(SOCK_NOSPACE, &con->sock->flags);
+                                       con->sock->sk->sk_write_pending++;
+                               }
                                cond_resched();
                                goto out;
                        }
                        if (ret <= 0)
                                goto send_error;
                }
-                       /* Don't starve people filling buffers */
+
+               /* Don't starve people filling buffers */
+               if (++count >= MAX_SEND_MSG_COUNT) {
                        cond_resched();
+                       count = 0;
+               }
 
                spin_lock(&con->writequeue_lock);
                e->offset += ret;
@@ -1430,20 +1468,19 @@ static void work_stop(void)
 
 static int work_start(void)
 {
-       int error;
-       recv_workqueue = create_workqueue("dlm_recv");
-       error = IS_ERR(recv_workqueue);
-       if (error) {
-               log_print("can't start dlm_recv %d", error);
-               return error;
+       recv_workqueue = alloc_workqueue("dlm_recv", WQ_MEM_RECLAIM |
+                                        WQ_HIGHPRI | WQ_FREEZEABLE, 0);
+       if (!recv_workqueue) {
+               log_print("can't start dlm_recv");
+               return -ENOMEM;
        }
 
-       send_workqueue = create_singlethread_workqueue("dlm_send");
-       error = IS_ERR(send_workqueue);
-       if (error) {
-               log_print("can't start dlm_send %d", error);
+       send_workqueue = alloc_workqueue("dlm_send", WQ_MEM_RECLAIM |
+                                        WQ_HIGHPRI | WQ_FREEZEABLE, 0);
+       if (!send_workqueue) {
+               log_print("can't start dlm_send");
                destroy_workqueue(recv_workqueue);
-               return error;
+               return -ENOMEM;
        }
 
        return 0;
index 6e07696308dc17a2c8ce26f852b04550d070175f..cf8d28d1fbadb90dd50725c950fa9f6f30bb426b 100644 (file)
@@ -251,6 +251,20 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
        kill_fasync(&fc->fasync, SIGIO, POLL_IN);
 }
 
+void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
+                      u64 nodeid, u64 nlookup)
+{
+       forget->forget_one.nodeid = nodeid;
+       forget->forget_one.nlookup = nlookup;
+
+       spin_lock(&fc->lock);
+       fc->forget_list_tail->next = forget;
+       fc->forget_list_tail = forget;
+       wake_up(&fc->waitq);
+       kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+       spin_unlock(&fc->lock);
+}
+
 static void flush_bg_queue(struct fuse_conn *fc)
 {
        while (fc->active_background < fc->max_background &&
@@ -438,12 +452,6 @@ static void fuse_request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
        }
 }
 
-void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
-{
-       req->isreply = 0;
-       fuse_request_send_nowait(fc, req);
-}
-
 void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
 {
        req->isreply = 1;
@@ -896,9 +904,15 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs,
        return err;
 }
 
+static int forget_pending(struct fuse_conn *fc)
+{
+       return fc->forget_list_head.next != NULL;
+}
+
 static int request_pending(struct fuse_conn *fc)
 {
-       return !list_empty(&fc->pending) || !list_empty(&fc->interrupts);
+       return !list_empty(&fc->pending) || !list_empty(&fc->interrupts) ||
+               forget_pending(fc);
 }
 
 /* Wait until a request is available on the pending list */
@@ -960,6 +974,120 @@ __releases(fc->lock)
        return err ? err : reqsize;
 }
 
+static struct fuse_forget_link *dequeue_forget(struct fuse_conn *fc,
+                                              unsigned max,
+                                              unsigned *countp)
+{
+       struct fuse_forget_link *head = fc->forget_list_head.next;
+       struct fuse_forget_link **newhead = &head;
+       unsigned count;
+
+       for (count = 0; *newhead != NULL && count < max; count++)
+               newhead = &(*newhead)->next;
+
+       fc->forget_list_head.next = *newhead;
+       *newhead = NULL;
+       if (fc->forget_list_head.next == NULL)
+               fc->forget_list_tail = &fc->forget_list_head;
+
+       if (countp != NULL)
+               *countp = count;
+
+       return head;
+}
+
+static int fuse_read_single_forget(struct fuse_conn *fc,
+                                  struct fuse_copy_state *cs,
+                                  size_t nbytes)
+__releases(fc->lock)
+{
+       int err;
+       struct fuse_forget_link *forget = dequeue_forget(fc, 1, NULL);
+       struct fuse_forget_in arg = {
+               .nlookup = forget->forget_one.nlookup,
+       };
+       struct fuse_in_header ih = {
+               .opcode = FUSE_FORGET,
+               .nodeid = forget->forget_one.nodeid,
+               .unique = fuse_get_unique(fc),
+               .len = sizeof(ih) + sizeof(arg),
+       };
+
+       spin_unlock(&fc->lock);
+       kfree(forget);
+       if (nbytes < ih.len)
+               return -EINVAL;
+
+       err = fuse_copy_one(cs, &ih, sizeof(ih));
+       if (!err)
+               err = fuse_copy_one(cs, &arg, sizeof(arg));
+       fuse_copy_finish(cs);
+
+       if (err)
+               return err;
+
+       return ih.len;
+}
+
+static int fuse_read_batch_forget(struct fuse_conn *fc,
+                                  struct fuse_copy_state *cs, size_t nbytes)
+__releases(fc->lock)
+{
+       int err;
+       unsigned max_forgets;
+       unsigned count;
+       struct fuse_forget_link *head;
+       struct fuse_batch_forget_in arg = { .count = 0 };
+       struct fuse_in_header ih = {
+               .opcode = FUSE_BATCH_FORGET,
+               .unique = fuse_get_unique(fc),
+               .len = sizeof(ih) + sizeof(arg),
+       };
+
+       if (nbytes < ih.len) {
+               spin_unlock(&fc->lock);
+               return -EINVAL;
+       }
+
+       max_forgets = (nbytes - ih.len) / sizeof(struct fuse_forget_one);
+       head = dequeue_forget(fc, max_forgets, &count);
+       spin_unlock(&fc->lock);
+
+       arg.count = count;
+       ih.len += count * sizeof(struct fuse_forget_one);
+       err = fuse_copy_one(cs, &ih, sizeof(ih));
+       if (!err)
+               err = fuse_copy_one(cs, &arg, sizeof(arg));
+
+       while (head) {
+               struct fuse_forget_link *forget = head;
+
+               if (!err) {
+                       err = fuse_copy_one(cs, &forget->forget_one,
+                                           sizeof(forget->forget_one));
+               }
+               head = forget->next;
+               kfree(forget);
+       }
+
+       fuse_copy_finish(cs);
+
+       if (err)
+               return err;
+
+       return ih.len;
+}
+
+static int fuse_read_forget(struct fuse_conn *fc, struct fuse_copy_state *cs,
+                           size_t nbytes)
+__releases(fc->lock)
+{
+       if (fc->minor < 16 || fc->forget_list_head.next->next == NULL)
+               return fuse_read_single_forget(fc, cs, nbytes);
+       else
+               return fuse_read_batch_forget(fc, cs, nbytes);
+}
+
 /*
  * Read a single request into the userspace filesystem's buffer.  This
  * function waits until a request is available, then removes it from
@@ -998,6 +1126,14 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
                return fuse_read_interrupt(fc, cs, nbytes, req);
        }
 
+       if (forget_pending(fc)) {
+               if (list_empty(&fc->pending) || fc->forget_batch-- > 0)
+                       return fuse_read_forget(fc, cs, nbytes);
+
+               if (fc->forget_batch <= -8)
+                       fc->forget_batch = 16;
+       }
+
        req = list_entry(fc->pending.next, struct fuse_req, list);
        req->state = FUSE_REQ_READING;
        list_move(&req->list, &fc->io);
@@ -1090,7 +1226,7 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
        if (!fc)
                return -EPERM;
 
-       bufs = kmalloc(pipe->buffers * sizeof (struct pipe_buffer), GFP_KERNEL);
+       bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL);
        if (!bufs)
                return -ENOMEM;
 
@@ -1626,7 +1762,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
        if (!fc)
                return -EPERM;
 
-       bufs = kmalloc(pipe->buffers * sizeof (struct pipe_buffer), GFP_KERNEL);
+       bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL);
        if (!bufs)
                return -ENOMEM;
 
@@ -1770,6 +1906,8 @@ __acquires(fc->lock)
        flush_bg_queue(fc);
        end_requests(fc, &fc->pending);
        end_requests(fc, &fc->processing);
+       while (forget_pending(fc))
+               kfree(dequeue_forget(fc, 1, NULL));
 }
 
 /*
index f738599fd8cd0b18e52d298513f5230c0359503c..042af7346ec127f757bdd913ccc2d924a4f55ae6 100644 (file)
@@ -10,9 +10,9 @@
 
 #include <linux/pagemap.h>
 #include <linux/file.h>
-#include <linux/gfp.h>
 #include <linux/sched.h>
 #include <linux/namei.h>
+#include <linux/slab.h>
 
 #if BITS_PER_LONG >= 64
 static inline void fuse_dentry_settime(struct dentry *entry, u64 time)
@@ -169,7 +169,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
                struct fuse_entry_out outarg;
                struct fuse_conn *fc;
                struct fuse_req *req;
-               struct fuse_req *forget_req;
+               struct fuse_forget_link *forget;
                struct dentry *parent;
                u64 attr_version;
 
@@ -182,8 +182,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
                if (IS_ERR(req))
                        return 0;
 
-               forget_req = fuse_get_req(fc);
-               if (IS_ERR(forget_req)) {
+               forget = fuse_alloc_forget();
+               if (!forget) {
                        fuse_put_request(fc, req);
                        return 0;
                }
@@ -203,15 +203,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
                if (!err) {
                        struct fuse_inode *fi = get_fuse_inode(inode);
                        if (outarg.nodeid != get_node_id(inode)) {
-                               fuse_send_forget(fc, forget_req,
-                                                outarg.nodeid, 1);
+                               fuse_queue_forget(fc, forget, outarg.nodeid, 1);
                                return 0;
                        }
                        spin_lock(&fc->lock);
                        fi->nlookup++;
                        spin_unlock(&fc->lock);
                }
-               fuse_put_request(fc, forget_req);
+               kfree(forget);
                if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
                        return 0;
 
@@ -263,7 +262,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
 {
        struct fuse_conn *fc = get_fuse_conn_super(sb);
        struct fuse_req *req;
-       struct fuse_req *forget_req;
+       struct fuse_forget_link *forget;
        u64 attr_version;
        int err;
 
@@ -277,9 +276,9 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
        if (IS_ERR(req))
                goto out;
 
-       forget_req = fuse_get_req(fc);
-       err = PTR_ERR(forget_req);
-       if (IS_ERR(forget_req)) {
+       forget = fuse_alloc_forget();
+       err = -ENOMEM;
+       if (!forget) {
                fuse_put_request(fc, req);
                goto out;
        }
@@ -305,13 +304,13 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
                           attr_version);
        err = -ENOMEM;
        if (!*inode) {
-               fuse_send_forget(fc, forget_req, outarg->nodeid, 1);
+               fuse_queue_forget(fc, forget, outarg->nodeid, 1);
                goto out;
        }
        err = 0;
 
  out_put_forget:
-       fuse_put_request(fc, forget_req);
+       kfree(forget);
  out:
        return err;
 }
@@ -378,7 +377,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        struct inode *inode;
        struct fuse_conn *fc = get_fuse_conn(dir);
        struct fuse_req *req;
-       struct fuse_req *forget_req;
+       struct fuse_forget_link *forget;
        struct fuse_create_in inarg;
        struct fuse_open_out outopen;
        struct fuse_entry_out outentry;
@@ -392,9 +391,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        if (flags & O_DIRECT)
                return -EINVAL;
 
-       forget_req = fuse_get_req(fc);
-       if (IS_ERR(forget_req))
-               return PTR_ERR(forget_req);
+       forget = fuse_alloc_forget();
+       if (!forget)
+               return -ENOMEM;
 
        req = fuse_get_req(fc);
        err = PTR_ERR(req);
@@ -452,10 +451,10 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        if (!inode) {
                flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
                fuse_sync_release(ff, flags);
-               fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
+               fuse_queue_forget(fc, forget, outentry.nodeid, 1);
                return -ENOMEM;
        }
-       fuse_put_request(fc, forget_req);
+       kfree(forget);
        d_instantiate(entry, inode);
        fuse_change_entry_timeout(entry, &outentry);
        fuse_invalidate_attr(dir);
@@ -473,7 +472,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
  out_put_request:
        fuse_put_request(fc, req);
  out_put_forget_req:
-       fuse_put_request(fc, forget_req);
+       kfree(forget);
        return err;
 }
 
@@ -487,12 +486,12 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
        struct fuse_entry_out outarg;
        struct inode *inode;
        int err;
-       struct fuse_req *forget_req;
+       struct fuse_forget_link *forget;
 
-       forget_req = fuse_get_req(fc);
-       if (IS_ERR(forget_req)) {
+       forget = fuse_alloc_forget();
+       if (!forget) {
                fuse_put_request(fc, req);
-               return PTR_ERR(forget_req);
+               return -ENOMEM;
        }
 
        memset(&outarg, 0, sizeof(outarg));
@@ -519,10 +518,10 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
        inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
                          &outarg.attr, entry_attr_timeout(&outarg), 0);
        if (!inode) {
-               fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
+               fuse_queue_forget(fc, forget, outarg.nodeid, 1);
                return -ENOMEM;
        }
-       fuse_put_request(fc, forget_req);
+       kfree(forget);
 
        if (S_ISDIR(inode->i_mode)) {
                struct dentry *alias;
@@ -545,7 +544,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
        return 0;
 
  out_put_forget_req:
-       fuse_put_request(fc, forget_req);
+       kfree(forget);
        return err;
 }
 
index 8b984a2cebbda185af01a6d4d5f8c31c89fc6fbe..95da1bc1c8267a78efce954c56e7f48eb1338d42 100644 (file)
@@ -1634,9 +1634,9 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
  * and 64bit.  Fortunately we can determine which structure the server
  * used from the size of the reply.
  */
-static int fuse_copy_ioctl_iovec(struct iovec *dst, void *src,
-                                size_t transferred, unsigned count,
-                                bool is_compat)
+static int fuse_copy_ioctl_iovec_old(struct iovec *dst, void *src,
+                                    size_t transferred, unsigned count,
+                                    bool is_compat)
 {
 #ifdef CONFIG_COMPAT
        if (count * sizeof(struct compat_iovec) == transferred) {
@@ -1680,6 +1680,42 @@ static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count)
        return 0;
 }
 
+static int fuse_copy_ioctl_iovec(struct fuse_conn *fc, struct iovec *dst,
+                                void *src, size_t transferred, unsigned count,
+                                bool is_compat)
+{
+       unsigned i;
+       struct fuse_ioctl_iovec *fiov = src;
+
+       if (fc->minor < 16) {
+               return fuse_copy_ioctl_iovec_old(dst, src, transferred,
+                                                count, is_compat);
+       }
+
+       if (count * sizeof(struct fuse_ioctl_iovec) != transferred)
+               return -EIO;
+
+       for (i = 0; i < count; i++) {
+               /* Did the server supply an inappropriate value? */
+               if (fiov[i].base != (unsigned long) fiov[i].base ||
+                   fiov[i].len != (unsigned long) fiov[i].len)
+                       return -EIO;
+
+               dst[i].iov_base = (void __user *) (unsigned long) fiov[i].base;
+               dst[i].iov_len = (size_t) fiov[i].len;
+
+#ifdef CONFIG_COMPAT
+               if (is_compat &&
+                   (ptr_to_compat(dst[i].iov_base) != fiov[i].base ||
+                    (compat_size_t) dst[i].iov_len != fiov[i].len))
+                       return -EIO;
+#endif
+       }
+
+       return 0;
+}
+
+
 /*
  * For ioctls, there is no generic way to determine how much memory
  * needs to be read and/or written.  Furthermore, ioctls are allowed
@@ -1740,18 +1776,25 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
        struct fuse_ioctl_out outarg;
        struct fuse_req *req = NULL;
        struct page **pages = NULL;
-       struct page *iov_page = NULL;
+       struct iovec *iov_page = NULL;
        struct iovec *in_iov = NULL, *out_iov = NULL;
        unsigned int in_iovs = 0, out_iovs = 0, num_pages = 0, max_pages;
        size_t in_size, out_size, transferred;
        int err;
 
+#if BITS_PER_LONG == 32
+       inarg.flags |= FUSE_IOCTL_32BIT;
+#else
+       if (flags & FUSE_IOCTL_COMPAT)
+               inarg.flags |= FUSE_IOCTL_32BIT;
+#endif
+
        /* assume all the iovs returned by client always fits in a page */
-       BUILD_BUG_ON(sizeof(struct iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE);
+       BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE);
 
        err = -ENOMEM;
        pages = kzalloc(sizeof(pages[0]) * FUSE_MAX_PAGES_PER_REQ, GFP_KERNEL);
-       iov_page = alloc_page(GFP_KERNEL);
+       iov_page = (struct iovec *) __get_free_page(GFP_KERNEL);
        if (!pages || !iov_page)
                goto out;
 
@@ -1760,7 +1803,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
         * RETRY from server is not allowed.
         */
        if (!(flags & FUSE_IOCTL_UNRESTRICTED)) {
-               struct iovec *iov = page_address(iov_page);
+               struct iovec *iov = iov_page;
 
                iov->iov_base = (void __user *)arg;
                iov->iov_len = _IOC_SIZE(cmd);
@@ -1841,7 +1884,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 
        /* did it ask for retry? */
        if (outarg.flags & FUSE_IOCTL_RETRY) {
-               char *vaddr;
+               void *vaddr;
 
                /* no retry if in restricted mode */
                err = -EIO;
@@ -1862,14 +1905,14 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
                        goto out;
 
                vaddr = kmap_atomic(pages[0], KM_USER0);
-               err = fuse_copy_ioctl_iovec(page_address(iov_page), vaddr,
+               err = fuse_copy_ioctl_iovec(fc, iov_page, vaddr,
                                            transferred, in_iovs + out_iovs,
                                            (flags & FUSE_IOCTL_COMPAT) != 0);
                kunmap_atomic(vaddr, KM_USER0);
                if (err)
                        goto out;
 
-               in_iov = page_address(iov_page);
+               in_iov = iov_page;
                out_iov = in_iov + in_iovs;
 
                err = fuse_verify_ioctl_iov(in_iov, in_iovs);
@@ -1891,8 +1934,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
  out:
        if (req)
                fuse_put_request(fc, req);
-       if (iov_page)
-               __free_page(iov_page);
+       free_page((unsigned long) iov_page);
        while (num_pages)
                __free_page(pages[--num_pages]);
        kfree(pages);
index 57d4a3a0f1023afa775ed07841e24c09c54130c1..ae5744a2f9e99a531551eb3704395d64ae08aee4 100644 (file)
@@ -53,6 +53,12 @@ extern struct mutex fuse_mutex;
 extern unsigned max_user_bgreq;
 extern unsigned max_user_congthresh;
 
+/* One forget request */
+struct fuse_forget_link {
+       struct fuse_forget_one forget_one;
+       struct fuse_forget_link *next;
+};
+
 /** FUSE inode */
 struct fuse_inode {
        /** Inode data */
@@ -66,7 +72,7 @@ struct fuse_inode {
        u64 nlookup;
 
        /** The request used for sending the FORGET message */
-       struct fuse_req *forget_req;
+       struct fuse_forget_link *forget;
 
        /** Time in jiffies until the file attributes are valid */
        u64 i_time;
@@ -255,7 +261,6 @@ struct fuse_req {
 
        /** Data for asynchronous requests */
        union {
-               struct fuse_forget_in forget_in;
                struct {
                        struct fuse_release_in in;
                        struct path path;
@@ -369,6 +374,13 @@ struct fuse_conn {
        /** Pending interrupts */
        struct list_head interrupts;
 
+       /** Queue of pending forgets */
+       struct fuse_forget_link forget_list_head;
+       struct fuse_forget_link *forget_list_tail;
+
+       /** Batching of FORGET requests (positive indicates FORGET batch) */
+       int forget_batch;
+
        /** Flag indicating if connection is blocked.  This will be
            the case before the INIT reply is received, and if there
            are too many outstading backgrounds requests */
@@ -543,8 +555,10 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
 /**
  * Send FORGET command
  */
-void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
-                     u64 nodeid, u64 nlookup);
+void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
+                      u64 nodeid, u64 nlookup);
+
+struct fuse_forget_link *fuse_alloc_forget(void);
 
 /**
  * Initialize READ or READDIR request
@@ -655,11 +669,6 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req);
  */
 void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req);
 
-/**
- * Send a request with no reply
- */
-void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
-
 /**
  * Send a request in the background
  */
index a8b31da19b93f52ad4ae5e4bd36244f961853f87..f62b32cffea9ee50a4cd9944e474aa56eecf85e0 100644 (file)
@@ -71,6 +71,11 @@ struct fuse_mount_data {
        unsigned blksize;
 };
 
+struct fuse_forget_link *fuse_alloc_forget()
+{
+       return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL);
+}
+
 static struct inode *fuse_alloc_inode(struct super_block *sb)
 {
        struct inode *inode;
@@ -90,8 +95,8 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
        INIT_LIST_HEAD(&fi->queued_writes);
        INIT_LIST_HEAD(&fi->writepages);
        init_waitqueue_head(&fi->page_waitq);
-       fi->forget_req = fuse_request_alloc();
-       if (!fi->forget_req) {
+       fi->forget = fuse_alloc_forget();
+       if (!fi->forget) {
                kmem_cache_free(fuse_inode_cachep, inode);
                return NULL;
        }
@@ -111,24 +116,10 @@ static void fuse_destroy_inode(struct inode *inode)
        struct fuse_inode *fi = get_fuse_inode(inode);
        BUG_ON(!list_empty(&fi->write_files));
        BUG_ON(!list_empty(&fi->queued_writes));
-       if (fi->forget_req)
-               fuse_request_free(fi->forget_req);
+       kfree(fi->forget);
        call_rcu(&inode->i_rcu, fuse_i_callback);
 }
 
-void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
-                     u64 nodeid, u64 nlookup)
-{
-       struct fuse_forget_in *inarg = &req->misc.forget_in;
-       inarg->nlookup = nlookup;
-       req->in.h.opcode = FUSE_FORGET;
-       req->in.h.nodeid = nodeid;
-       req->in.numargs = 1;
-       req->in.args[0].size = sizeof(struct fuse_forget_in);
-       req->in.args[0].value = inarg;
-       fuse_request_send_noreply(fc, req);
-}
-
 static void fuse_evict_inode(struct inode *inode)
 {
        truncate_inode_pages(&inode->i_data, 0);
@@ -136,8 +127,8 @@ static void fuse_evict_inode(struct inode *inode)
        if (inode->i_sb->s_flags & MS_ACTIVE) {
                struct fuse_conn *fc = get_fuse_conn(inode);
                struct fuse_inode *fi = get_fuse_inode(inode);
-               fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup);
-               fi->forget_req = NULL;
+               fuse_queue_forget(fc, fi->forget, fi->nodeid, fi->nlookup);
+               fi->forget = NULL;
        }
 }
 
@@ -541,6 +532,7 @@ void fuse_conn_init(struct fuse_conn *fc)
        INIT_LIST_HEAD(&fc->interrupts);
        INIT_LIST_HEAD(&fc->bg_queue);
        INIT_LIST_HEAD(&fc->entry);
+       fc->forget_list_tail = &fc->forget_list_head;
        atomic_set(&fc->num_waiting, 0);
        fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND;
        fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD;
index 8d3d2b4a0a7d64431d63edff082cbedbd5b2543b..a79790c06275fb0e328b85107b39ccfc7a63ce31 100644 (file)
@@ -11,6 +11,7 @@
 #define __INCORE_DOT_H__
 
 #include <linux/fs.h>
+#include <linux/kobject.h>
 #include <linux/workqueue.h>
 #include <linux/dlm.h>
 #include <linux/buffer_head.h>
index d182438c7ae4bea8b4ae108ad910ee795417410a..5d799c13205f5e46e2ae0acb920b866fc92829bf 100644 (file)
@@ -22,7 +22,8 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
                return -ENOMEM;
        fd->search_key = ptr;
        fd->key = ptr + tree->max_key_len + 2;
-       dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0));
+       dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n",
+               tree->cnid, __builtin_return_address(0));
        mutex_lock(&tree->tree_lock);
        return 0;
 }
@@ -31,7 +32,8 @@ void hfs_find_exit(struct hfs_find_data *fd)
 {
        hfs_bnode_put(fd->bnode);
        kfree(fd->search_key);
-       dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0));
+       dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n",
+               fd->tree->cnid, __builtin_return_address(0));
        mutex_unlock(&fd->tree->tree_lock);
        fd->tree = NULL;
 }
index ad57f5991eb1f14e3ac24dafa207e440d6d74be3..1cad80c789cb42e5ebada89cc294c9e07fde0d22 100644 (file)
@@ -15,7 +15,8 @@
 
 #define PAGE_CACHE_BITS        (PAGE_CACHE_SIZE * 8)
 
-int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *max)
+int hfsplus_block_allocate(struct super_block *sb, u32 size,
+               u32 offset, u32 *max)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        struct page *page;
index 29da6574ba77941b22c15b4e959cd4c84b8bbee1..1c42cc5b899f31de94d2cf9dfd24c5e4d451c895 100644 (file)
@@ -42,7 +42,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
 u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
 {
        __be16 data;
-       // optimize later...
+       /* TODO: optimize later... */
        hfs_bnode_read(node, &data, off, 2);
        return be16_to_cpu(data);
 }
@@ -50,7 +50,7 @@ u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
 u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
 {
        u8 data;
-       // optimize later...
+       /* TODO: optimize later... */
        hfs_bnode_read(node, &data, off, 1);
        return data;
 }
@@ -96,7 +96,7 @@ void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
 void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data)
 {
        __be16 v = cpu_to_be16(data);
-       // optimize later...
+       /* TODO: optimize later... */
        hfs_bnode_write(node, &v, off, 2);
 }
 
@@ -212,7 +212,8 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
                                dst_page--;
                        }
                        src -= len;
-                       memmove(kmap(*dst_page) + src, kmap(*src_page) + src, len);
+                       memmove(kmap(*dst_page) + src,
+                               kmap(*src_page) + src, len);
                        kunmap(*src_page);
                        set_page_dirty(*dst_page);
                        kunmap(*dst_page);
@@ -250,14 +251,16 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
 
                if (src == dst) {
                        l = min(len, (int)PAGE_CACHE_SIZE - src);
-                       memmove(kmap(*dst_page) + src, kmap(*src_page) + src, l);
+                       memmove(kmap(*dst_page) + src,
+                               kmap(*src_page) + src, l);
                        kunmap(*src_page);
                        set_page_dirty(*dst_page);
                        kunmap(*dst_page);
 
                        while ((len -= l) != 0) {
                                l = min(len, (int)PAGE_CACHE_SIZE);
-                               memmove(kmap(*++dst_page), kmap(*++src_page), l);
+                               memmove(kmap(*++dst_page),
+                                       kmap(*++src_page), l);
                                kunmap(*src_page);
                                set_page_dirty(*dst_page);
                                kunmap(*dst_page);
@@ -268,7 +271,8 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
                        do {
                                src_ptr = kmap(*src_page) + src;
                                dst_ptr = kmap(*dst_page) + dst;
-                               if (PAGE_CACHE_SIZE - src < PAGE_CACHE_SIZE - dst) {
+                               if (PAGE_CACHE_SIZE - src <
+                                               PAGE_CACHE_SIZE - dst) {
                                        l = PAGE_CACHE_SIZE - src;
                                        src = 0;
                                        dst += l;
@@ -340,7 +344,8 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
                        return;
                tmp->next = node->next;
                cnid = cpu_to_be32(tmp->next);
-               hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
+               hfs_bnode_write(tmp, &cnid,
+                       offsetof(struct hfs_bnode_desc, next), 4);
                hfs_bnode_put(tmp);
        } else if (node->type == HFS_NODE_LEAF)
                tree->leaf_head = node->next;
@@ -351,15 +356,15 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
                        return;
                tmp->prev = node->prev;
                cnid = cpu_to_be32(tmp->prev);
-               hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, prev), 4);
+               hfs_bnode_write(tmp, &cnid,
+                       offsetof(struct hfs_bnode_desc, prev), 4);
                hfs_bnode_put(tmp);
        } else if (node->type == HFS_NODE_LEAF)
                tree->leaf_tail = node->prev;
 
-       // move down?
-       if (!node->prev && !node->next) {
-               printk(KERN_DEBUG "hfs_btree_del_level\n");
-       }
+       /* move down? */
+       if (!node->prev && !node->next)
+               dprint(DBG_BNODE_MOD, "hfs_btree_del_level\n");
        if (!node->parent) {
                tree->root = 0;
                tree->depth = 0;
@@ -379,16 +384,16 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid)
        struct hfs_bnode *node;
 
        if (cnid >= tree->node_count) {
-               printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid);
+               printk(KERN_ERR "hfs: request for non-existent node "
+                               "%d in B*Tree\n",
+                       cnid);
                return NULL;
        }
 
        for (node = tree->node_hash[hfs_bnode_hash(cnid)];
-            node; node = node->next_hash) {
-               if (node->this == cnid) {
+                       node; node = node->next_hash)
+               if (node->this == cnid)
                        return node;
-               }
-       }
        return NULL;
 }
 
@@ -402,7 +407,9 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
        loff_t off;
 
        if (cnid >= tree->node_count) {
-               printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid);
+               printk(KERN_ERR "hfs: request for non-existent node "
+                               "%d in B*Tree\n",
+                       cnid);
                return NULL;
        }
 
@@ -429,7 +436,8 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
        } else {
                spin_unlock(&tree->hash_lock);
                kfree(node);
-               wait_event(node2->lock_wq, !test_bit(HFS_BNODE_NEW, &node2->flags));
+               wait_event(node2->lock_wq,
+                       !test_bit(HFS_BNODE_NEW, &node2->flags));
                return node2;
        }
        spin_unlock(&tree->hash_lock);
@@ -483,7 +491,8 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
        if (node) {
                hfs_bnode_get(node);
                spin_unlock(&tree->hash_lock);
-               wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags));
+               wait_event(node->lock_wq,
+                       !test_bit(HFS_BNODE_NEW, &node->flags));
                if (test_bit(HFS_BNODE_ERROR, &node->flags))
                        goto node_error;
                return node;
@@ -497,7 +506,8 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
        if (!test_bit(HFS_BNODE_NEW, &node->flags))
                return node;
 
-       desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) + node->page_offset);
+       desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) +
+                       node->page_offset);
        node->prev = be32_to_cpu(desc->prev);
        node->next = be32_to_cpu(desc->next);
        node->num_recs = be16_to_cpu(desc->num_recs);
@@ -556,11 +566,13 @@ node_error:
 
 void hfs_bnode_free(struct hfs_bnode *node)
 {
-       //int i;
+#if 0
+       int i;
 
-       //for (i = 0; i < node->tree->pages_per_bnode; i++)
-       //      if (node->page[i])
-       //              page_cache_release(node->page[i]);
+       for (i = 0; i < node->tree->pages_per_bnode; i++)
+               if (node->page[i])
+                       page_cache_release(node->page[i]);
+#endif
        kfree(node);
 }
 
@@ -607,7 +619,8 @@ void hfs_bnode_get(struct hfs_bnode *node)
        if (node) {
                atomic_inc(&node->refcnt);
                dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
-                      node->tree->cnid, node->this, atomic_read(&node->refcnt));
+                       node->tree->cnid, node->this,
+                       atomic_read(&node->refcnt));
        }
 }
 
@@ -619,7 +632,8 @@ void hfs_bnode_put(struct hfs_bnode *node)
                int i;
 
                dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
-                      node->tree->cnid, node->this, atomic_read(&node->refcnt));
+                       node->tree->cnid, node->this,
+                       atomic_read(&node->refcnt));
                BUG_ON(!atomic_read(&node->refcnt));
                if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
                        return;
index 2f39d05443e1a374b197359f70d20337562aa9e8..2312de34bd426e0755516042881d3be31ddc33a0 100644 (file)
@@ -39,7 +39,8 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
           !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
                retval = node->tree->max_key_len + 2;
        } else {
-               recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
+               recoff = hfs_bnode_read_u16(node,
+                       node->tree->node_size - (rec + 1) * 2);
                if (!recoff)
                        return 0;
 
@@ -84,7 +85,8 @@ again:
        end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
        end_off = hfs_bnode_read_u16(node, end_rec_off);
        end_rec_off -= 2;
-       dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", rec, size, end_off, end_rec_off);
+       dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
+               rec, size, end_off, end_rec_off);
        if (size > end_rec_off - end_off) {
                if (new_node)
                        panic("not enough room!\n");
@@ -99,7 +101,9 @@ again:
        }
        node->num_recs++;
        /* write new last offset */
-       hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
+       hfs_bnode_write_u16(node,
+               offsetof(struct hfs_bnode_desc, num_recs),
+               node->num_recs);
        hfs_bnode_write_u16(node, end_rec_off, end_off + size);
        data_off = end_off;
        data_rec_off = end_rec_off + 2;
@@ -151,7 +155,8 @@ skip:
                if (tree->attributes & HFS_TREE_VARIDXKEYS)
                        key_len = be16_to_cpu(fd->search_key->key_len) + 2;
                else {
-                       fd->search_key->key_len = cpu_to_be16(tree->max_key_len);
+                       fd->search_key->key_len =
+                               cpu_to_be16(tree->max_key_len);
                        key_len = tree->max_key_len + 2;
                }
                goto again;
@@ -180,7 +185,8 @@ again:
                mark_inode_dirty(tree->inode);
        }
        hfs_bnode_dump(node);
-       dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n", fd->record, fd->keylength + fd->entrylength);
+       dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n",
+               fd->record, fd->keylength + fd->entrylength);
        if (!--node->num_recs) {
                hfs_bnode_unlink(node);
                if (!node->parent)
@@ -194,7 +200,9 @@ again:
                __hfs_brec_find(node, fd);
                goto again;
        }
-       hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
+       hfs_bnode_write_u16(node,
+               offsetof(struct hfs_bnode_desc, num_recs),
+               node->num_recs);
 
        if (rec_off == end_off)
                goto skip;
@@ -364,7 +372,8 @@ again:
                newkeylen = hfs_bnode_read_u16(node, 14) + 2;
        else
                fd->keylength = newkeylen = tree->max_key_len + 2;
-       dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n", rec, fd->keylength, newkeylen);
+       dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n",
+               rec, fd->keylength, newkeylen);
 
        rec_off = tree->node_size - (rec + 2) * 2;
        end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
@@ -375,7 +384,7 @@ again:
                end_off = hfs_bnode_read_u16(parent, end_rec_off);
                if (end_rec_off - end_off < diff) {
 
-                       printk(KERN_DEBUG "hfs: splitting index node...\n");
+                       dprint(DBG_BNODE_MOD, "hfs: splitting index node.\n");
                        fd->bnode = parent;
                        new_node = hfs_bnode_split(fd);
                        if (IS_ERR(new_node))
@@ -383,7 +392,8 @@ again:
                        parent = fd->bnode;
                        rec = fd->record;
                        rec_off = tree->node_size - (rec + 2) * 2;
-                       end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
+                       end_rec_off = tree->node_size -
+                               (parent->num_recs + 1) * 2;
                }
        }
 
index 22e4d4e329999c3ba9848036a3639bc194598f74..21023d9f8ff3d2a9d87b67c6c69efe5606d182ab 100644 (file)
@@ -51,7 +51,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
                goto free_inode;
 
        /* Load the header */
-       head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
+       head = (struct hfs_btree_header_rec *)(kmap(page) +
+               sizeof(struct hfs_bnode_desc));
        tree->root = be32_to_cpu(head->root);
        tree->leaf_count = be32_to_cpu(head->leaf_count);
        tree->leaf_head = be32_to_cpu(head->leaf_head);
@@ -115,7 +116,9 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
 
        tree->node_size_shift = ffs(size) - 1;
 
-       tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       tree->pages_per_bnode =
+               (tree->node_size + PAGE_CACHE_SIZE - 1) >>
+               PAGE_CACHE_SHIFT;
 
        kunmap(page);
        page_cache_release(page);
@@ -144,8 +147,10 @@ void hfs_btree_close(struct hfs_btree *tree)
                while ((node = tree->node_hash[i])) {
                        tree->node_hash[i] = node->next_hash;
                        if (atomic_read(&node->refcnt))
-                               printk(KERN_CRIT "hfs: node %d:%d still has %d user(s)!\n",
-                                       node->tree->cnid, node->this, atomic_read(&node->refcnt));
+                               printk(KERN_CRIT "hfs: node %d:%d "
+                                               "still has %d user(s)!\n",
+                                       node->tree->cnid, node->this,
+                                       atomic_read(&node->refcnt));
                        hfs_bnode_free(node);
                        tree->node_hash_cnt--;
                }
@@ -166,7 +171,8 @@ void hfs_btree_write(struct hfs_btree *tree)
                return;
        /* Load the header */
        page = node->page[0];
-       head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
+       head = (struct hfs_btree_header_rec *)(kmap(page) +
+               sizeof(struct hfs_bnode_desc));
 
        head->root = cpu_to_be32(tree->root);
        head->leaf_count = cpu_to_be32(tree->leaf_count);
@@ -272,7 +278,8 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
                                                tree->free_nodes--;
                                                mark_inode_dirty(tree->inode);
                                                hfs_bnode_put(node);
-                                               return hfs_bnode_create(tree, idx);
+                                               return hfs_bnode_create(tree,
+                                                       idx);
                                        }
                                }
                        }
@@ -287,7 +294,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
                kunmap(*pagep);
                nidx = node->next;
                if (!nidx) {
-                       printk(KERN_DEBUG "hfs: create new bmap node...\n");
+                       dprint(DBG_BNODE_MOD, "hfs: create new bmap node.\n");
                        next_node = hfs_bmap_new_bmap(node, idx);
                } else
                        next_node = hfs_bnode_find(tree, nidx);
@@ -329,7 +336,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
                hfs_bnode_put(node);
                if (!i) {
                        /* panic */;
-                       printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this);
+                       printk(KERN_CRIT "hfs: unable to free bnode %u. "
+                                       "bmap not found!\n",
+                               node->this);
                        return;
                }
                node = hfs_bnode_find(tree, i);
@@ -337,7 +346,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
                        return;
                if (node->type != HFS_NODE_MAP) {
                        /* panic */;
-                       printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type);
+                       printk(KERN_CRIT "hfs: invalid bmap found! "
+                                       "(%u,%d)\n",
+                               node->this, node->type);
                        hfs_bnode_put(node);
                        return;
                }
@@ -350,7 +361,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
        m = 1 << (~nidx & 7);
        byte = data[off];
        if (!(byte & m)) {
-               printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type);
+               printk(KERN_CRIT "hfs: trying to free free bnode "
+                               "%u(%d)\n",
+                       node->this, node->type);
                kunmap(page);
                hfs_bnode_put(node);
                return;
index 8af45fc5b051abb3353501441fa9ea9030d9395a..b4ba1b3193336ead42c6ffbfbbd365e058cf8f1e 100644 (file)
@@ -91,7 +91,8 @@ void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms)
                perms->dev = 0;
 }
 
-static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct inode *inode)
+static int hfsplus_cat_build_record(hfsplus_cat_entry *entry,
+               u32 cnid, struct inode *inode)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
 
@@ -128,20 +129,32 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
                if (cnid == inode->i_ino) {
                        hfsplus_cat_set_perms(inode, &file->permissions);
                        if (S_ISLNK(inode->i_mode)) {
-                               file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE);
-                               file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR);
+                               file->user_info.fdType =
+                                       cpu_to_be32(HFSP_SYMLINK_TYPE);
+                               file->user_info.fdCreator =
+                                       cpu_to_be32(HFSP_SYMLINK_CREATOR);
                        } else {
-                               file->user_info.fdType = cpu_to_be32(sbi->type);
-                               file->user_info.fdCreator = cpu_to_be32(sbi->creator);
+                               file->user_info.fdType =
+                                       cpu_to_be32(sbi->type);
+                               file->user_info.fdCreator =
+                                       cpu_to_be32(sbi->creator);
                        }
-                       if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
-                               file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
+                       if (HFSPLUS_FLG_IMMUTABLE &
+                                       (file->permissions.rootflags |
+                                       file->permissions.userflags))
+                               file->flags |=
+                                       cpu_to_be16(HFSPLUS_FILE_LOCKED);
                } else {
-                       file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE);
-                       file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR);
-                       file->user_info.fdFlags = cpu_to_be16(0x100);
-                       file->create_date = HFSPLUS_I(sbi->hidden_dir)->create_date;
-                       file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode)->linkid);
+                       file->user_info.fdType =
+                               cpu_to_be32(HFSP_HARDLINK_TYPE);
+                       file->user_info.fdCreator =
+                               cpu_to_be32(HFSP_HFSPLUS_CREATOR);
+                       file->user_info.fdFlags =
+                               cpu_to_be16(0x100);
+                       file->create_date =
+                               HFSPLUS_I(sbi->hidden_dir)->create_date;
+                       file->permissions.dev =
+                               cpu_to_be32(HFSPLUS_I(inode)->linkid);
                }
                return sizeof(*file);
        }
@@ -182,12 +195,14 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
                return -EIO;
        }
 
-       hfsplus_cat_build_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID),
-                                &tmp.thread.nodeName);
+       hfsplus_cat_build_key_uni(fd->search_key,
+               be32_to_cpu(tmp.thread.parentID),
+               &tmp.thread.nodeName);
        return hfs_brec_find(fd);
 }
 
-int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode)
+int hfsplus_create_cat(u32 cnid, struct inode *dir,
+               struct qstr *str, struct inode *inode)
 {
        struct super_block *sb = dir->i_sb;
        struct hfs_find_data fd;
@@ -195,13 +210,15 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
        int entry_size;
        int err;
 
-       dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink);
+       dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n",
+               str->name, cnid, inode->i_nlink);
        hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
 
        hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
-       entry_size = hfsplus_fill_cat_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
+       entry_size = hfsplus_fill_cat_thread(sb, &entry,
+               S_ISDIR(inode->i_mode) ?
                        HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD,
-                       dir->i_ino, str);
+               dir->i_ino, str);
        err = hfs_brec_find(&fd);
        if (err != -ENOENT) {
                if (!err)
@@ -227,7 +244,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
 
        dir->i_size++;
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(dir);
+       hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
+
        hfs_find_exit(&fd);
        return 0;
 
@@ -249,7 +267,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
        int err, off;
        u16 type;
 
-       dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
+       dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n",
+               str ? str->name : NULL, cnid);
        hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
 
        if (!str) {
@@ -260,11 +279,15 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
                if (err)
                        goto out;
 
-               off = fd.entryoffset + offsetof(struct hfsplus_cat_thread, nodeName);
+               off = fd.entryoffset +
+                       offsetof(struct hfsplus_cat_thread, nodeName);
                fd.search_key->cat.parent = cpu_to_be32(dir->i_ino);
-               hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.length, off, 2);
+               hfs_bnode_read(fd.bnode,
+                       &fd.search_key->cat.name.length, off, 2);
                len = be16_to_cpu(fd.search_key->cat.name.length) * 2;
-               hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.unicode, off + 2, len);
+               hfs_bnode_read(fd.bnode,
+                       &fd.search_key->cat.name.unicode,
+                       off + 2, len);
                fd.search_key->key_len = cpu_to_be16(6 + len);
        } else
                hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
@@ -281,7 +304,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
                hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA);
 #endif
 
-               off = fd.entryoffset + offsetof(struct hfsplus_cat_file, rsrc_fork);
+               off = fd.entryoffset +
+                       offsetof(struct hfsplus_cat_file, rsrc_fork);
                hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork));
                hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC);
        }
@@ -308,7 +332,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
 
        dir->i_size--;
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(dir);
+       hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
 out:
        hfs_find_exit(&fd);
 
@@ -325,7 +349,8 @@ int hfsplus_rename_cat(u32 cnid,
        int entry_size, type;
        int err = 0;
 
-       dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name,
+       dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
+               cnid, src_dir->i_ino, src_name->name,
                dst_dir->i_ino, dst_name->name);
        hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
        dst_fd = src_fd;
@@ -353,7 +378,6 @@ int hfsplus_rename_cat(u32 cnid,
                goto out;
        dst_dir->i_size++;
        dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(dst_dir);
 
        /* finally remove the old entry */
        hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
@@ -365,7 +389,6 @@ int hfsplus_rename_cat(u32 cnid,
                goto out;
        src_dir->i_size--;
        src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(src_dir);
 
        /* remove old thread entry */
        hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL);
@@ -379,7 +402,8 @@ int hfsplus_rename_cat(u32 cnid,
 
        /* create new thread entry */
        hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
-       entry_size = hfsplus_fill_cat_thread(sb, &entry, type, dst_dir->i_ino, dst_name);
+       entry_size = hfsplus_fill_cat_thread(sb, &entry, type,
+               dst_dir->i_ino, dst_name);
        err = hfs_brec_find(&dst_fd);
        if (err != -ENOENT) {
                if (!err)
@@ -387,6 +411,9 @@ int hfsplus_rename_cat(u32 cnid,
                goto out;
        }
        err = hfs_brec_insert(&dst_fd, &entry, entry_size);
+
+       hfsplus_mark_inode_dirty(dst_dir, HFSPLUS_I_CAT_DIRTY);
+       hfsplus_mark_inode_dirty(src_dir, HFSPLUS_I_CAT_DIRTY);
 out:
        hfs_bnode_put(dst_fd.bnode);
        hfs_find_exit(&src_fd);
index ccab87145f7aa4f9beeda9008142fcd31496c7ed..f896dc843026a278317116c86bd7fa2c75f6cd25 100644 (file)
@@ -66,11 +66,17 @@ again:
                        goto fail;
                }
                cnid = be32_to_cpu(entry.file.id);
-               if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) &&
-                   entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
-                   (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->create_date ||
-                    entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode)->create_date) &&
-                   HFSPLUS_SB(sb)->hidden_dir) {
+               if (entry.file.user_info.fdType ==
+                               cpu_to_be32(HFSP_HARDLINK_TYPE) &&
+                               entry.file.user_info.fdCreator ==
+                               cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
+                               (entry.file.create_date ==
+                                       HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->
+                                               create_date ||
+                               entry.file.create_date ==
+                                       HFSPLUS_I(sb->s_root->d_inode)->
+                                               create_date) &&
+                               HFSPLUS_SB(sb)->hidden_dir) {
                        struct qstr str;
                        char name[32];
 
@@ -83,11 +89,13 @@ again:
                                linkid = 0;
                        } else {
                                dentry->d_fsdata = (void *)(unsigned long)cnid;
-                               linkid = be32_to_cpu(entry.file.permissions.dev);
+                               linkid =
+                                       be32_to_cpu(entry.file.permissions.dev);
                                str.len = sprintf(name, "iNode%d", linkid);
                                str.name = name;
                                hfsplus_cat_build_key(sb, fd.search_key,
-                                       HFSPLUS_SB(sb)->hidden_dir->i_ino, &str);
+                                       HFSPLUS_SB(sb)->hidden_dir->i_ino,
+                                       &str);
                                goto again;
                        }
                } else if (!dentry->d_fsdata)
@@ -139,7 +147,8 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
                filp->f_pos++;
                /* fall through */
        case 1:
-               hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
+               hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
+                       fd.entrylength);
                if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) {
                        printk(KERN_ERR "hfs: bad catalog folder thread\n");
                        err = -EIO;
@@ -169,14 +178,16 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        err = -EIO;
                        goto out;
                }
-               hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
+               hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
+                       fd.entrylength);
                type = be16_to_cpu(entry.type);
                len = HFSPLUS_MAX_STRLEN;
                err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len);
                if (err)
                        goto out;
                if (type == HFSPLUS_FOLDER) {
-                       if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) {
+                       if (fd.entrylength <
+                                       sizeof(struct hfsplus_cat_folder)) {
                                printk(KERN_ERR "hfs: small dir entry\n");
                                err = -EIO;
                                goto out;
@@ -202,7 +213,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        err = -EIO;
                        goto out;
                }
-       next:
+next:
                filp->f_pos++;
                if (filp->f_pos >= inode->i_size)
                        goto out;
@@ -273,7 +284,8 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
                HFSPLUS_I(inode)->linkid = id;
                cnid = sbi->next_cnid++;
                src_dentry->d_fsdata = (void *)(unsigned long)cnid;
-               res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode);
+               res = hfsplus_create_cat(cnid, src_dir,
+                       &src_dentry->d_name, inode);
                if (res)
                        /* panic? */
                        goto out;
@@ -485,6 +497,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
 };
 
 const struct file_operations hfsplus_dir_operations = {
+       .fsync          = hfsplus_file_fsync,
        .read           = generic_read_dir,
        .readdir        = hfsplus_readdir,
        .unlocked_ioctl = hfsplus_ioctl,
index 0c9cb1820a523fae02c6bf2f37e6fbdc5c5dceeb..52a0bcaa7b6d7596302d8e2dcf7fba09229c38fd 100644 (file)
@@ -83,7 +83,8 @@ static u32 hfsplus_ext_lastblock(struct hfsplus_extent *ext)
        return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count);
 }
 
-static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd)
+static void __hfsplus_ext_write_extent(struct inode *inode,
+               struct hfs_find_data *fd)
 {
        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        int res;
@@ -95,24 +96,32 @@ static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data
                                HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
 
        res = hfs_brec_find(fd);
-       if (hip->flags & HFSPLUS_FLG_EXT_NEW) {
+       if (hip->extent_state & HFSPLUS_EXT_NEW) {
                if (res != -ENOENT)
                        return;
                hfs_brec_insert(fd, hip->cached_extents,
                                sizeof(hfsplus_extent_rec));
-               hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
+               hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
        } else {
                if (res)
                        return;
                hfs_bnode_write(fd->bnode, hip->cached_extents,
                                fd->entryoffset, fd->entrylength);
-               hip->flags &= ~HFSPLUS_FLG_EXT_DIRTY;
+               hip->extent_state &= ~HFSPLUS_EXT_DIRTY;
        }
+
+       /*
+        * We can't just use hfsplus_mark_inode_dirty here, because we
+        * also get called from hfsplus_write_inode, which should not
+        * redirty the inode.  Instead the callers have to be careful
+        * to explicily mark the inode dirty, too.
+        */
+       set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags);
 }
 
 static void hfsplus_ext_write_extent_locked(struct inode *inode)
 {
-       if (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_EXT_DIRTY) {
+       if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) {
                struct hfs_find_data fd;
 
                hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
@@ -144,18 +153,20 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
                return -ENOENT;
        if (fd->entrylength != sizeof(hfsplus_extent_rec))
                return -EIO;
-       hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfsplus_extent_rec));
+       hfs_bnode_read(fd->bnode, extent, fd->entryoffset,
+               sizeof(hfsplus_extent_rec));
        return 0;
 }
 
-static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block)
+static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd,
+               struct inode *inode, u32 block)
 {
        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        int res;
 
        WARN_ON(!mutex_is_locked(&hip->extents_lock));
 
-       if (hip->flags & HFSPLUS_FLG_EXT_DIRTY)
+       if (hip->extent_state & HFSPLUS_EXT_DIRTY)
                __hfsplus_ext_write_extent(inode, fd);
 
        res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino,
@@ -164,10 +175,11 @@ static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct in
                                                HFSPLUS_TYPE_DATA);
        if (!res) {
                hip->cached_start = be32_to_cpu(fd->key->ext.start_block);
-               hip->cached_blocks = hfsplus_ext_block_count(hip->cached_extents);
+               hip->cached_blocks =
+                       hfsplus_ext_block_count(hip->cached_extents);
        } else {
                hip->cached_start = hip->cached_blocks = 0;
-               hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
+               hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
        }
        return res;
 }
@@ -197,6 +209,7 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        int res = -EIO;
        u32 ablock, dblock, mask;
+       int was_dirty = 0;
        int shift;
 
        /* Convert inode block to disk allocation block */
@@ -223,27 +236,37 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
                return -EIO;
 
        mutex_lock(&hip->extents_lock);
+
+       /*
+        * hfsplus_ext_read_extent will write out a cached extent into
+        * the extents btree.  In that case we may have to mark the inode
+        * dirty even for a pure read of an extent here.
+        */
+       was_dirty = (hip->extent_state & HFSPLUS_EXT_DIRTY);
        res = hfsplus_ext_read_extent(inode, ablock);
-       if (!res) {
-               dblock = hfsplus_ext_find_block(hip->cached_extents,
-                                               ablock - hip->cached_start);
-       } else {
+       if (res) {
                mutex_unlock(&hip->extents_lock);
                return -EIO;
        }
+       dblock = hfsplus_ext_find_block(hip->cached_extents,
+                                       ablock - hip->cached_start);
        mutex_unlock(&hip->extents_lock);
 
 done:
-       dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", inode->i_ino, (long long)iblock, dblock);
+       dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n",
+               inode->i_ino, (long long)iblock, dblock);
        mask = (1 << sbi->fs_shift) - 1;
-       map_bh(bh_result, sb, (dblock << sbi->fs_shift) + sbi->blockoffset + (iblock & mask));
+       map_bh(bh_result, sb,
+               (dblock << sbi->fs_shift) + sbi->blockoffset +
+                       (iblock & mask));
        if (create) {
                set_buffer_new(bh_result);
                hip->phys_size += sb->s_blocksize;
                hip->fs_blocks++;
                inode_add_bytes(inode, sb->s_blocksize);
-               mark_inode_dirty(inode);
        }
+       if (create || was_dirty)
+               mark_inode_dirty(inode);
        return 0;
 }
 
@@ -326,7 +349,8 @@ found:
        }
 }
 
-int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw *fork, int type)
+int hfsplus_free_fork(struct super_block *sb, u32 cnid,
+               struct hfsplus_fork_raw *fork, int type)
 {
        struct hfs_find_data fd;
        hfsplus_extent_rec ext_entry;
@@ -373,12 +397,13 @@ int hfsplus_file_extend(struct inode *inode)
        u32 start, len, goal;
        int res;
 
-       if (sbi->alloc_file->i_size * 8 <
-           sbi->total_blocks - sbi->free_blocks + 8) {
-               // extend alloc file
-               printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n",
-                               sbi->alloc_file->i_size * 8,
-                               sbi->total_blocks, sbi->free_blocks);
+       if (sbi->total_blocks - sbi->free_blocks + 8 >
+                       sbi->alloc_file->i_size * 8) {
+               /* extend alloc file */
+               printk(KERN_ERR "hfs: extend alloc file! "
+                               "(%llu,%u,%u)\n",
+                       sbi->alloc_file->i_size * 8,
+                       sbi->total_blocks, sbi->free_blocks);
                return -ENOSPC;
        }
 
@@ -429,7 +454,7 @@ int hfsplus_file_extend(struct inode *inode)
                                         start, len);
                if (!res) {
                        hfsplus_dump_extent(hip->cached_extents);
-                       hip->flags |= HFSPLUS_FLG_EXT_DIRTY;
+                       hip->extent_state |= HFSPLUS_EXT_DIRTY;
                        hip->cached_blocks += len;
                } else if (res == -ENOSPC)
                        goto insert_extent;
@@ -438,7 +463,7 @@ out:
        mutex_unlock(&hip->extents_lock);
        if (!res) {
                hip->alloc_blocks += len;
-               mark_inode_dirty(inode);
+               hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
        }
        return res;
 
@@ -450,7 +475,7 @@ insert_extent:
        hip->cached_extents[0].start_block = cpu_to_be32(start);
        hip->cached_extents[0].block_count = cpu_to_be32(len);
        hfsplus_dump_extent(hip->cached_extents);
-       hip->flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW;
+       hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW;
        hip->cached_start = hip->alloc_blocks;
        hip->cached_blocks = len;
 
@@ -466,8 +491,9 @@ void hfsplus_file_truncate(struct inode *inode)
        u32 alloc_cnt, blk_cnt, start;
        int res;
 
-       dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n",
-               inode->i_ino, (long long)hip->phys_size, inode->i_size);
+       dprint(DBG_INODE, "truncate: %lu, %llu -> %llu\n",
+               inode->i_ino, (long long)hip->phys_size,
+               inode->i_size);
 
        if (inode->i_size > hip->phys_size) {
                struct address_space *mapping = inode->i_mapping;
@@ -481,7 +507,8 @@ void hfsplus_file_truncate(struct inode *inode)
                                                &page, &fsdata);
                if (res)
                        return;
-               res = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata);
+               res = pagecache_write_end(NULL, mapping, size,
+                       0, 0, page, fsdata);
                if (res < 0)
                        return;
                mark_inode_dirty(inode);
@@ -513,12 +540,12 @@ void hfsplus_file_truncate(struct inode *inode)
                                     alloc_cnt - start, alloc_cnt - blk_cnt);
                hfsplus_dump_extent(hip->cached_extents);
                if (blk_cnt > start) {
-                       hip->flags |= HFSPLUS_FLG_EXT_DIRTY;
+                       hip->extent_state |= HFSPLUS_EXT_DIRTY;
                        break;
                }
                alloc_cnt = start;
                hip->cached_start = hip->cached_blocks = 0;
-               hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
+               hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
                hfs_brec_remove(&fd);
        }
        hfs_find_exit(&fd);
@@ -527,7 +554,8 @@ void hfsplus_file_truncate(struct inode *inode)
        hip->alloc_blocks = blk_cnt;
 out:
        hip->phys_size = inode->i_size;
-       hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+       hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >>
+               sb->s_blocksize_bits;
        inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
-       mark_inode_dirty(inode);
+       hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
 }
index a5308f491e3ef5c3b65d62bcaaf3b29ce51c42da..d6857523336d21412ec50bb0a8c8039526ab6adb 100644 (file)
 #define DBG_EXTENT     0x00000020
 #define DBG_BITMAP     0x00000040
 
-//#define DBG_MASK     (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
-//#define DBG_MASK     (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
-//#define DBG_MASK     (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
+#if 0
+#define DBG_MASK       (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
+#define DBG_MASK       (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
+#define DBG_MASK       (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
+#endif
 #define DBG_MASK       (0)
 
 #define dprint(flg, fmt, args...) \
-       if (flg & DBG_MASK) printk(fmt , ## args)
+       if (flg & DBG_MASK) \
+               printk(fmt , ## args)
 
 /* Runtime config options */
 #define HFSPLUS_DEF_CR_TYPE    0x3F3F3F3F  /* '????' */
@@ -37,7 +40,8 @@
 #define HFSPLUS_TYPE_DATA 0x00
 #define HFSPLUS_TYPE_RSRC 0xFF
 
-typedef int (*btree_keycmp)(const hfsplus_btree_key *, const hfsplus_btree_key *);
+typedef int (*btree_keycmp)(const hfsplus_btree_key *,
+               const hfsplus_btree_key *);
 
 #define NODE_HASH_SIZE 256
 
@@ -61,7 +65,6 @@ struct hfs_btree {
        unsigned int max_key_len;
        unsigned int depth;
 
-       //unsigned int map1_size, map_size;
        struct mutex tree_lock;
 
        unsigned int pages_per_bnode;
@@ -107,8 +110,8 @@ struct hfsplus_vh;
 struct hfs_btree;
 
 struct hfsplus_sb_info {
-       struct buffer_head *s_vhbh;
        struct hfsplus_vh *s_vhdr;
+       struct hfsplus_vh *s_backup_vhdr;
        struct hfs_btree *ext_tree;
        struct hfs_btree *cat_tree;
        struct hfs_btree *attr_tree;
@@ -118,7 +121,8 @@ struct hfsplus_sb_info {
 
        /* Runtime variables */
        u32 blockoffset;
-       u32 sect_count;
+       sector_t part_start;
+       sector_t sect_count;
        int fs_shift;
 
        /* immutable data from the volume header */
@@ -155,6 +159,12 @@ struct hfsplus_sb_info {
 #define HFSPLUS_SB_FORCE       2
 #define HFSPLUS_SB_HFSX                3
 #define HFSPLUS_SB_CASEFOLD    4
+#define HFSPLUS_SB_NOBARRIER   5
+
+static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
+{
+       return sb->s_fs_info;
+}
 
 
 struct hfsplus_inode_info {
@@ -170,7 +180,7 @@ struct hfsplus_inode_info {
        u32 cached_blocks;
        hfsplus_extent_rec first_extents;
        hfsplus_extent_rec cached_extents;
-       unsigned long flags;
+       unsigned int extent_state;
        struct mutex extents_lock;
 
        /*
@@ -184,6 +194,11 @@ struct hfsplus_inode_info {
         */
        u32 linkid;
 
+       /*
+        * Accessed using atomic bitops.
+        */
+       unsigned long flags;
+
        /*
         * Protected by i_mutex.
         */
@@ -195,12 +210,34 @@ struct hfsplus_inode_info {
        struct inode vfs_inode;
 };
 
-#define HFSPLUS_FLG_RSRC       0x0001
-#define HFSPLUS_FLG_EXT_DIRTY  0x0002
-#define HFSPLUS_FLG_EXT_NEW    0x0004
+#define HFSPLUS_EXT_DIRTY      0x0001
+#define HFSPLUS_EXT_NEW                0x0002
+
+#define HFSPLUS_I_RSRC         0       /* represents a resource fork */
+#define HFSPLUS_I_CAT_DIRTY    1       /* has changes in the catalog tree */
+#define HFSPLUS_I_EXT_DIRTY    2       /* has changes in the extent tree */
+#define HFSPLUS_I_ALLOC_DIRTY  3       /* has changes in the allocation file */
+
+#define HFSPLUS_IS_RSRC(inode) \
+       test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags)
+
+static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
+{
+       return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
+}
 
-#define HFSPLUS_IS_DATA(inode)   (!(HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC))
-#define HFSPLUS_IS_RSRC(inode)   (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC)
+/*
+ * Mark an inode dirty, and also mark the btree in which the
+ * specific type of metadata is stored.
+ * For data or metadata that gets written back by into the catalog btree
+ * by hfsplus_write_inode a plain mark_inode_dirty call is enough.
+ */
+static inline void hfsplus_mark_inode_dirty(struct inode *inode,
+               unsigned int flag)
+{
+       set_bit(flag, &HFSPLUS_I(inode)->flags);
+       mark_inode_dirty(inode);
+}
 
 struct hfs_find_data {
        /* filled by caller */
@@ -318,9 +355,12 @@ int hfs_brec_read(struct hfs_find_data *, void *, int);
 int hfs_brec_goto(struct hfs_find_data *, int);
 
 /* catalog.c */
-int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
-int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
-void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *);
+int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *,
+               const hfsplus_btree_key *);
+int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *,
+               const hfsplus_btree_key *);
+void hfsplus_cat_build_key(struct super_block *sb,
+               hfsplus_btree_key *, u32, struct qstr *);
 int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *);
 int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *);
 int hfsplus_delete_cat(u32, struct inode *, struct qstr *);
@@ -336,7 +376,8 @@ extern const struct file_operations hfsplus_dir_operations;
 int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
 void hfsplus_ext_write_extent(struct inode *);
 int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int);
-int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int);
+int hfsplus_free_fork(struct super_block *, u32,
+               struct hfsplus_fork_raw *, int);
 int hfsplus_file_extend(struct inode *);
 void hfsplus_file_truncate(struct inode *);
 
@@ -351,6 +392,7 @@ int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *);
 int hfsplus_cat_write_inode(struct inode *);
 struct inode *hfsplus_new_inode(struct super_block *, int);
 void hfsplus_delete_inode(struct inode *);
+int hfsplus_file_fsync(struct file *file, int datasync);
 
 /* ioctl.c */
 long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
@@ -362,6 +404,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
 
 /* options.c */
 int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
+int hfsplus_parse_options_remount(char *input, int *force);
 void hfsplus_fill_defaults(struct hfsplus_sb_info *);
 int hfsplus_show_options(struct seq_file *, struct vfsmount *);
 
@@ -375,12 +418,16 @@ extern u16 hfsplus_decompose_table[];
 extern u16 hfsplus_compose_table[];
 
 /* unicode.c */
-int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
-int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
-int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *);
-int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
-int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *str);
+int hfsplus_strcasecmp(const struct hfsplus_unistr *,
+               const struct hfsplus_unistr *);
+int hfsplus_strcmp(const struct hfsplus_unistr *,
+               const struct hfsplus_unistr *);
+int hfsplus_uni2asc(struct super_block *,
+               const struct hfsplus_unistr *, char *, int *);
+int hfsplus_asc2uni(struct super_block *,
+               struct hfsplus_unistr *, const char *, int);
+int hfsplus_hash_dentry(const struct dentry *dentry,
+               const struct inode *inode, struct qstr *str);
 int hfsplus_compare_dentry(const struct dentry *parent,
                const struct inode *pinode,
                const struct dentry *dentry, const struct inode *inode,
@@ -388,36 +435,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
 
 /* wrapper.c */
 int hfsplus_read_wrapper(struct super_block *);
-
 int hfs_part_find(struct super_block *, sector_t *, sector_t *);
-
-/* access macros */
-static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
-{
-       return sb->s_fs_info;
-}
-
-static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
-{
-       return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
-}
-
-#define sb_bread512(sb, sec, data) ({                  \
-       struct buffer_head *__bh;                       \
-       sector_t __block;                               \
-       loff_t __start;                                 \
-       int __offset;                                   \
-                                                       \
-       __start = (loff_t)(sec) << HFSPLUS_SECTOR_SHIFT;\
-       __block = __start >> (sb)->s_blocksize_bits;    \
-       __offset = __start & ((sb)->s_blocksize - 1);   \
-       __bh = sb_bread((sb), __block);                 \
-       if (likely(__bh != NULL))                       \
-               data = (void *)(__bh->b_data + __offset);\
-       else                                            \
-               data = NULL;                            \
-       __bh;                                           \
-})
+int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
+               void *data, int rw);
 
 /* time macros */
 #define __hfsp_mt2ut(t)                (be32_to_cpu(t) - 2082844800U)
index 6892899fd6fbbabce55d3fe1f2c8915fe3f33d89..927cdd6d5bf59b667f6b43ca00c0c0e5034e55b7 100644 (file)
@@ -36,7 +36,8 @@
 #define HFSP_WRAPOFF_EMBEDSIG     0x7C
 #define HFSP_WRAPOFF_EMBEDEXT     0x7E
 
-#define HFSP_HIDDENDIR_NAME    "\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80HFS+ Private Data"
+#define HFSP_HIDDENDIR_NAME \
+       "\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80HFS+ Private Data"
 
 #define HFSP_HARDLINK_TYPE     0x686c6e6b      /* 'hlnk' */
 #define HFSP_HFSPLUS_CREATOR   0x6866732b      /* 'hfs+' */
index 8afd7e84f98d5d0417b8c256d60f0ff0329521db..a8df651747f0eadaa8af44dffda657f2d64aea3d 100644 (file)
@@ -8,6 +8,7 @@
  * Inode handling routines
  */
 
+#include <linux/blkdev.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
@@ -77,7 +78,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
        if (!tree)
                return 0;
        if (tree->node_size >= PAGE_CACHE_SIZE) {
-               nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT);
+               nidx = page->index >>
+                       (tree->node_size_shift - PAGE_CACHE_SHIFT);
                spin_lock(&tree->hash_lock);
                node = hfs_bnode_findhash(tree, nidx);
                if (!node)
@@ -90,7 +92,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
                }
                spin_unlock(&tree->hash_lock);
        } else {
-               nidx = page->index << (PAGE_CACHE_SHIFT - tree->node_size_shift);
+               nidx = page->index <<
+                       (PAGE_CACHE_SHIFT - tree->node_size_shift);
                i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
                spin_lock(&tree->hash_lock);
                do {
@@ -166,8 +169,8 @@ const struct dentry_operations hfsplus_dentry_operations = {
        .d_compare    = hfsplus_compare_dentry,
 };
 
-static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry,
-                                         struct nameidata *nd)
+static struct dentry *hfsplus_file_lookup(struct inode *dir,
+               struct dentry *dentry, struct nameidata *nd)
 {
        struct hfs_find_data fd;
        struct super_block *sb = dir->i_sb;
@@ -190,7 +193,9 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
        inode->i_ino = dir->i_ino;
        INIT_LIST_HEAD(&hip->open_dir_list);
        mutex_init(&hip->extents_lock);
-       hip->flags = HFSPLUS_FLG_RSRC;
+       hip->extent_state = 0;
+       hip->flags = 0;
+       set_bit(HFSPLUS_I_RSRC, &hip->flags);
 
        hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
        err = hfsplus_find_cat(sb, dir->i_ino, &fd);
@@ -219,7 +224,8 @@ out:
        return NULL;
 }
 
-static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir)
+static void hfsplus_get_perms(struct inode *inode,
+               struct hfsplus_perm *perms, int dir)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
        u16 mode;
@@ -302,29 +308,41 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
        return 0;
 }
 
-static int hfsplus_file_fsync(struct file *filp, int datasync)
+int hfsplus_file_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = filp->f_mapping->host;
-       struct super_block * sb;
-       int ret, err;
-
-       /* sync the inode to buffers */
-       ret = write_inode_now(inode, 0);
-
-       /* sync the superblock to buffers */
-       sb = inode->i_sb;
-       if (sb->s_dirt) {
-               if (!(sb->s_flags & MS_RDONLY))
-                       hfsplus_sync_fs(sb, 1);
-               else
-                       sb->s_dirt = 0;
+       struct inode *inode = file->f_mapping->host;
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
+       int error = 0, error2;
+
+       /*
+        * Sync inode metadata into the catalog and extent trees.
+        */
+       sync_inode_metadata(inode, 1);
+
+       /*
+        * And explicitly write out the btrees.
+        */
+       if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags))
+               error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
+
+       if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) {
+               error2 =
+                       filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
+               if (!error)
+                       error = error2;
        }
 
-       /* .. finally sync the buffers to disk */
-       err = sync_blockdev(sb->s_bdev);
-       if (!ret)
-               ret = err;
-       return ret;
+       if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) {
+               error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
+               if (!error)
+                       error = error2;
+       }
+
+       if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
+               blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
+
+       return error;
 }
 
 static const struct inode_operations hfsplus_file_inode_operations = {
@@ -337,7 +355,7 @@ static const struct inode_operations hfsplus_file_inode_operations = {
 };
 
 static const struct file_operations hfsplus_file_operations = {
-       .llseek         = generic_file_llseek,
+       .llseek         = generic_file_llseek,
        .read           = do_sync_read,
        .aio_read       = generic_file_aio_read,
        .write          = do_sync_write,
@@ -370,6 +388,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
        INIT_LIST_HEAD(&hip->open_dir_list);
        mutex_init(&hip->extents_lock);
        atomic_set(&hip->opencnt, 0);
+       hip->extent_state = 0;
        hip->flags = 0;
        memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
        memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
@@ -457,7 +476,8 @@ void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
        }
 }
 
-void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
+void hfsplus_inode_write_fork(struct inode *inode,
+               struct hfsplus_fork_raw *fork)
 {
        memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
               sizeof(hfsplus_extent_rec));
@@ -499,13 +519,14 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
                hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
                                        sizeof(struct hfsplus_cat_file));
 
-               hfsplus_inode_read_fork(inode, HFSPLUS_IS_DATA(inode) ?
-                                       &file->data_fork : &file->rsrc_fork);
+               hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ?
+                                       &file->rsrc_fork : &file->data_fork);
                hfsplus_get_perms(inode, &file->permissions, 0);
                inode->i_nlink = 1;
                if (S_ISREG(inode->i_mode)) {
                        if (file->permissions.dev)
-                               inode->i_nlink = be32_to_cpu(file->permissions.dev);
+                               inode->i_nlink =
+                                       be32_to_cpu(file->permissions.dev);
                        inode->i_op = &hfsplus_file_inode_operations;
                        inode->i_fop = &hfsplus_file_operations;
                        inode->i_mapping->a_ops = &hfsplus_aops;
@@ -578,7 +599,9 @@ int hfsplus_cat_write_inode(struct inode *inode)
                                        sizeof(struct hfsplus_cat_file));
                hfsplus_inode_write_fork(inode, &file->data_fork);
                hfsplus_cat_set_perms(inode, &file->permissions);
-               if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
+               if (HFSPLUS_FLG_IMMUTABLE &
+                               (file->permissions.rootflags |
+                                       file->permissions.userflags))
                        file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
                else
                        file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
@@ -588,6 +611,8 @@ int hfsplus_cat_write_inode(struct inode *inode)
                hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
                                         sizeof(struct hfsplus_cat_file));
        }
+
+       set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
 out:
        hfs_find_exit(&fd);
        return 0;
index 40a85a3ded6efe6a0a17d08fe2b068ba6b4e369a..508ce662ce122b0b5bea34f6f6260ae22ef0a512 100644 (file)
@@ -28,7 +28,7 @@ static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
 
        if (inode->i_flags & S_IMMUTABLE)
                flags |= FS_IMMUTABLE_FL;
-       if (inode->i_flags |= S_APPEND)
+       if (inode->i_flags & S_APPEND)
                flags |= FS_APPEND_FL;
        if (hip->userflags & HFSPLUS_FLG_NODUMP)
                flags |= FS_NODUMP_FL;
@@ -147,9 +147,11 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
                        res = -ERANGE;
        } else
                res = -EOPNOTSUPP;
-       if (!res)
+       if (!res) {
                hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
                                sizeof(struct hfsplus_cat_file));
+               hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
+       }
 out:
        hfs_find_exit(&fd);
        return res;
index f9ab276a4d8de9e15d2acf49a358da1a9ff10fe6..bb62a5882147e7c800f21b6173126a6dfa51e1f3 100644 (file)
@@ -23,6 +23,7 @@ enum {
        opt_umask, opt_uid, opt_gid,
        opt_part, opt_session, opt_nls,
        opt_nodecompose, opt_decompose,
+       opt_barrier, opt_nobarrier,
        opt_force, opt_err
 };
 
@@ -37,6 +38,8 @@ static const match_table_t tokens = {
        { opt_nls, "nls=%s" },
        { opt_decompose, "decompose" },
        { opt_nodecompose, "nodecompose" },
+       { opt_barrier, "barrier" },
+       { opt_nobarrier, "nobarrier" },
        { opt_force, "force" },
        { opt_err, NULL }
 };
@@ -65,6 +68,32 @@ static inline int match_fourchar(substring_t *arg, u32 *result)
        return 0;
 }
 
+int hfsplus_parse_options_remount(char *input, int *force)
+{
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int token;
+
+       if (!input)
+               return 0;
+
+       while ((p = strsep(&input, ",")) != NULL) {
+               if (!*p)
+                       continue;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case opt_force:
+                       *force = 1;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 1;
+}
+
 /* Parse options from mount. Returns 0 on failure */
 /* input is the options passed to mount() as a string */
 int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
@@ -136,7 +165,9 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
                        if (p)
                                sbi->nls = load_nls(p);
                        if (!sbi->nls) {
-                               printk(KERN_ERR "hfs: unable to load nls mapping \"%s\"\n", p);
+                               printk(KERN_ERR "hfs: unable to load "
+                                               "nls mapping \"%s\"\n",
+                                       p);
                                kfree(p);
                                return 0;
                        }
@@ -148,6 +179,12 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
                case opt_nodecompose:
                        set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
                        break;
+               case opt_barrier:
+                       clear_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags);
+                       break;
+               case opt_nobarrier:
+                       set_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags);
+                       break;
                case opt_force:
                        set_bit(HFSPLUS_SB_FORCE, &sbi->flags);
                        break;
@@ -177,7 +214,8 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
                seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator);
        if (sbi->type != HFSPLUS_DEF_CR_TYPE)
                seq_printf(seq, ",type=%.4s", (char *)&sbi->type);
-       seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, sbi->uid, sbi->gid);
+       seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask,
+               sbi->uid, sbi->gid);
        if (sbi->part >= 0)
                seq_printf(seq, ",part=%u", sbi->part);
        if (sbi->session >= 0)
@@ -186,5 +224,7 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
                seq_printf(seq, ",nls=%s", sbi->nls->charset);
        if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags))
                seq_printf(seq, ",nodecompose");
+       if (test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
+               seq_printf(seq, ",nobarrier");
        return 0;
 }
index 208b16c645cc234c6f5ce1b15fbd5b49ba802ee8..d66ad113b1cc4e265f8af88f0ac50536b9ca6743 100644 (file)
@@ -2,7 +2,8 @@
  * linux/fs/hfsplus/part_tbl.c
  *
  * Copyright (C) 1996-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
+ * This file may be distributed under the terms of
+ * the GNU General Public License.
  *
  * Original code to handle the new style Mac partition table based on
  * a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
@@ -13,6 +14,7 @@
  *
  */
 
+#include <linux/slab.h>
 #include "hfsplus_fs.h"
 
 /* offsets to various blocks */
@@ -58,77 +60,94 @@ struct new_pmap {
  */
 struct old_pmap {
        __be16          pdSig;  /* Signature bytes */
-       struct  old_pmap_entry {
+       struct old_pmap_entry {
                __be32  pdStart;
                __be32  pdSize;
                __be32  pdFSID;
        }       pdEntry[42];
 } __packed;
 
+static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm,
+               sector_t *part_start, sector_t *part_size)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+       int i;
+
+       for (i = 0; i < 42; i++) {
+               struct old_pmap_entry *p = &pm->pdEntry[i];
+
+               if (p->pdStart && p->pdSize &&
+                   p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
+                   (sbi->part < 0 || sbi->part == i)) {
+                       *part_start += be32_to_cpu(p->pdStart);
+                       *part_size = be32_to_cpu(p->pdSize);
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+
+static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm,
+               sector_t *part_start, sector_t *part_size)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+       int size = be32_to_cpu(pm->pmMapBlkCnt);
+       int res;
+       int i = 0;
+
+       do {
+               if (!memcmp(pm->pmPartType, "Apple_HFS", 9) &&
+                   (sbi->part < 0 || sbi->part == i)) {
+                       *part_start += be32_to_cpu(pm->pmPyPartStart);
+                       *part_size = be32_to_cpu(pm->pmPartBlkCnt);
+                       return 0;
+               }
+
+               if (++i >= size)
+                       return -ENOENT;
+
+               res = hfsplus_submit_bio(sb->s_bdev,
+                                        *part_start + HFS_PMAP_BLK + i,
+                                        pm, READ);
+               if (res)
+                       return res;
+       } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC));
+
+       return -ENOENT;
+}
+
 /*
- * hfs_part_find()
- *
- * Parse the partition map looking for the
- * start and length of the 'part'th HFS partition.
+ * Parse the partition map looking for the start and length of a
+ * HFS/HFS+ partition.
  */
 int hfs_part_find(struct super_block *sb,
-                 sector_t *part_start, sector_t *part_size)
+               sector_t *part_start, sector_t *part_size)
 {
-       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
-       struct buffer_head *bh;
-       __be16 *data;
-       int i, size, res;
+       void *data;
+       int res;
+
+       data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
-       res = -ENOENT;
-       bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK, data);
-       if (!bh)
-               return -EIO;
+       res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK,
+                                data, READ);
+       if (res)
+               return res;
 
-       switch (be16_to_cpu(*data)) {
+       switch (be16_to_cpu(*((__be16 *)data))) {
        case HFS_OLD_PMAP_MAGIC:
-         {
-               struct old_pmap *pm;
-               struct old_pmap_entry *p;
-
-               pm = (struct old_pmap *)bh->b_data;
-               p = pm->pdEntry;
-               size = 42;
-               for (i = 0; i < size; p++, i++) {
-                       if (p->pdStart && p->pdSize &&
-                           p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
-                           (sbi->part < 0 || sbi->part == i)) {
-                               *part_start += be32_to_cpu(p->pdStart);
-                               *part_size = be32_to_cpu(p->pdSize);
-                               res = 0;
-                       }
-               }
+               res = hfs_parse_old_pmap(sb, data, part_start, part_size);
                break;
-         }
        case HFS_NEW_PMAP_MAGIC:
-         {
-               struct new_pmap *pm;
-
-               pm = (struct new_pmap *)bh->b_data;
-               size = be32_to_cpu(pm->pmMapBlkCnt);
-               for (i = 0; i < size;) {
-                       if (!memcmp(pm->pmPartType,"Apple_HFS", 9) &&
-                           (sbi->part < 0 || sbi->part == i)) {
-                               *part_start += be32_to_cpu(pm->pmPyPartStart);
-                               *part_size = be32_to_cpu(pm->pmPartBlkCnt);
-                               res = 0;
-                               break;
-                       }
-                       brelse(bh);
-                       bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK + ++i, pm);
-                       if (!bh)
-                               return -EIO;
-                       if (pm->pmSig != cpu_to_be16(HFS_NEW_PMAP_MAGIC))
-                               break;
-               }
+               res = hfs_parse_new_pmap(sb, data, part_start, part_size);
+               break;
+       default:
+               res = -ENOENT;
                break;
-         }
        }
-       brelse(bh);
 
+       kfree(data);
        return res;
 }
index ddf712e4700e278ec43ad7c94be6fe51c9ef8a3b..6ee6ad20acf25128da6524fab5675d97eb07b61f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pagemap.h>
+#include <linux/blkdev.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/vfs.h>
@@ -66,6 +67,7 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
        INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
        mutex_init(&HFSPLUS_I(inode)->extents_lock);
        HFSPLUS_I(inode)->flags = 0;
+       HFSPLUS_I(inode)->extent_state = 0;
        HFSPLUS_I(inode)->rsrc_inode = NULL;
        atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
 
@@ -157,45 +159,65 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        struct hfsplus_vh *vhdr = sbi->s_vhdr;
+       int write_backup = 0;
+       int error, error2;
+
+       if (!wait)
+               return 0;
 
        dprint(DBG_SUPER, "hfsplus_write_super\n");
 
-       mutex_lock(&sbi->vh_mutex);
-       mutex_lock(&sbi->alloc_mutex);
        sb->s_dirt = 0;
 
+       /*
+        * Explicitly write out the special metadata inodes.
+        *
+        * While these special inodes are marked as hashed and written
+        * out peridocically by the flusher threads we redirty them
+        * during writeout of normal inodes, and thus the life lock
+        * prevents us from getting the latest state to disk.
+        */
+       error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
+       error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
+       if (!error)
+               error = error2;
+       error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
+       if (!error)
+               error = error2;
+
+       mutex_lock(&sbi->vh_mutex);
+       mutex_lock(&sbi->alloc_mutex);
        vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
        vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
        vhdr->folder_count = cpu_to_be32(sbi->folder_count);
        vhdr->file_count = cpu_to_be32(sbi->file_count);
 
-       mark_buffer_dirty(sbi->s_vhbh);
        if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
-               if (sbi->sect_count) {
-                       struct buffer_head *bh;
-                       u32 block, offset;
-
-                       block = sbi->blockoffset;
-                       block += (sbi->sect_count - 2) >> (sb->s_blocksize_bits - 9);
-                       offset = ((sbi->sect_count - 2) << 9) & (sb->s_blocksize - 1);
-                       printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n",
-                                         sbi->blockoffset, sbi->sect_count,
-                                         block, offset);
-                       bh = sb_bread(sb, block);
-                       if (bh) {
-                               vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
-                               if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) {
-                                       memcpy(vhdr, sbi->s_vhdr, sizeof(*vhdr));
-                                       mark_buffer_dirty(bh);
-                                       brelse(bh);
-                               } else
-                                       printk(KERN_WARNING "hfs: backup not found!\n");
-                       }
-               }
+               memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr));
+               write_backup = 1;
        }
+
+       error2 = hfsplus_submit_bio(sb->s_bdev,
+                                  sbi->part_start + HFSPLUS_VOLHEAD_SECTOR,
+                                  sbi->s_vhdr, WRITE_SYNC);
+       if (!error)
+               error = error2;
+       if (!write_backup)
+               goto out;
+
+       error2 = hfsplus_submit_bio(sb->s_bdev,
+                                 sbi->part_start + sbi->sect_count - 2,
+                                 sbi->s_backup_vhdr, WRITE_SYNC);
+       if (!error)
+               error2 = error;
+out:
        mutex_unlock(&sbi->alloc_mutex);
        mutex_unlock(&sbi->vh_mutex);
-       return 0;
+
+       if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
+               blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL);
+
+       return error;
 }
 
 static void hfsplus_write_super(struct super_block *sb)
@@ -215,23 +237,22 @@ static void hfsplus_put_super(struct super_block *sb)
        if (!sb->s_fs_info)
                return;
 
-       if (sb->s_dirt)
-               hfsplus_write_super(sb);
        if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
                struct hfsplus_vh *vhdr = sbi->s_vhdr;
 
                vhdr->modify_date = hfsp_now2mt();
                vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT);
                vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT);
-               mark_buffer_dirty(sbi->s_vhbh);
-               sync_dirty_buffer(sbi->s_vhbh);
+
+               hfsplus_sync_fs(sb, 1);
        }
 
        hfs_btree_close(sbi->cat_tree);
        hfs_btree_close(sbi->ext_tree);
        iput(sbi->alloc_file);
        iput(sbi->hidden_dir);
-       brelse(sbi->s_vhbh);
+       kfree(sbi->s_vhdr);
+       kfree(sbi->s_backup_vhdr);
        unload_nls(sbi->nls);
        kfree(sb->s_fs_info);
        sb->s_fs_info = NULL;
@@ -263,26 +284,31 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
                return 0;
        if (!(*flags & MS_RDONLY)) {
                struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr;
-               struct hfsplus_sb_info sbi;
+               int force = 0;
 
-               memset(&sbi, 0, sizeof(struct hfsplus_sb_info));
-               sbi.nls = HFSPLUS_SB(sb)->nls;
-               if (!hfsplus_parse_options(data, &sbi))
+               if (!hfsplus_parse_options_remount(data, &force))
                        return -EINVAL;
 
                if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
-                       printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, "
-                              "running fsck.hfsplus is recommended.  leaving read-only.\n");
+                       printk(KERN_WARNING "hfs: filesystem was "
+                                       "not cleanly unmounted, "
+                                       "running fsck.hfsplus is recommended.  "
+                                       "leaving read-only.\n");
                        sb->s_flags |= MS_RDONLY;
                        *flags |= MS_RDONLY;
-               } else if (test_bit(HFSPLUS_SB_FORCE, &sbi.flags)) {
+               } else if (force) {
                        /* nothing */
-               } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
-                       printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n");
+               } else if (vhdr->attributes &
+                               cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
+                       printk(KERN_WARNING "hfs: filesystem is marked locked, "
+                                       "leaving read-only.\n");
                        sb->s_flags |= MS_RDONLY;
                        *flags |= MS_RDONLY;
-               } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
-                       printk(KERN_WARNING "hfs: filesystem is marked journaled, leaving read-only.\n");
+               } else if (vhdr->attributes &
+                               cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
+                       printk(KERN_WARNING "hfs: filesystem is "
+                                       "marked journaled, "
+                                       "leaving read-only.\n");
                        sb->s_flags |= MS_RDONLY;
                        *flags |= MS_RDONLY;
                }
@@ -372,17 +398,22 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_maxbytes = MAX_LFS_FILESIZE;
 
        if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
-               printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, "
-                      "running fsck.hfsplus is recommended.  mounting read-only.\n");
+               printk(KERN_WARNING "hfs: Filesystem was "
+                               "not cleanly unmounted, "
+                               "running fsck.hfsplus is recommended.  "
+                               "mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
        } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
                /* nothing */
        } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
                printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
-       } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) && !(sb->s_flags & MS_RDONLY)) {
-               printk(KERN_WARNING "hfs: write access to a journaled filesystem is not supported, "
-                      "use the force option at your own risk, mounting read-only.\n");
+       } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) &&
+                       !(sb->s_flags & MS_RDONLY)) {
+               printk(KERN_WARNING "hfs: write access to "
+                               "a journaled filesystem is not supported, "
+                               "use the force option at your own risk, "
+                               "mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
        }
 
@@ -449,19 +480,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        be32_add_cpu(&vhdr->write_count, 1);
        vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
        vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
-       mark_buffer_dirty(sbi->s_vhbh);
-       sync_dirty_buffer(sbi->s_vhbh);
+       hfsplus_sync_fs(sb, 1);
 
        if (!sbi->hidden_dir) {
-               printk(KERN_DEBUG "hfs: create hidden dir...\n");
-
                mutex_lock(&sbi->vh_mutex);
                sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
                hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode,
                                   &str, sbi->hidden_dir);
                mutex_unlock(&sbi->vh_mutex);
 
-               mark_inode_dirty(sbi->hidden_dir);
+               hfsplus_mark_inode_dirty(sbi->hidden_dir, HFSPLUS_I_CAT_DIRTY);
        }
 out:
        unload_nls(sbi->nls);
index d800aa0f2c80d9324018cb89ff9dfeb897e6b048..a3f0bfcc881ef588d0d95e9d9fbd46ad61a32c4e 100644 (file)
 /* Returns folded char, or 0 if ignorable */
 static inline u16 case_fold(u16 c)
 {
-        u16 tmp;
-
-        tmp = hfsplus_case_fold_table[c >> 8];
-        if (tmp)
-                tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
-        else
-                tmp = c;
-        return tmp;
+       u16 tmp;
+
+       tmp = hfsplus_case_fold_table[c >> 8];
+       if (tmp)
+               tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
+       else
+               tmp = c;
+       return tmp;
 }
 
 /* Compare unicode strings, return values like normal strcmp */
@@ -118,7 +118,9 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
        return NULL;
 }
 
-int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p)
+int hfsplus_uni2asc(struct super_block *sb,
+               const struct hfsplus_unistr *ustr,
+               char *astr, int *len_p)
 {
        const hfsplus_unichr *ip;
        struct nls_table *nls = HFSPLUS_SB(sb)->nls;
@@ -171,7 +173,8 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
                                goto same;
                        c1 = be16_to_cpu(*ip);
                        if (likely(compose))
-                               ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c1);
+                               ce1 = hfsplus_compose_lookup(
+                                       hfsplus_compose_table, c1);
                        if (ce1)
                                break;
                        switch (c0) {
@@ -199,7 +202,8 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
                if (ce2) {
                        i = 1;
                        while (i < ustrlen) {
-                               ce1 = hfsplus_compose_lookup(ce2, be16_to_cpu(ip[i]));
+                               ce1 = hfsplus_compose_lookup(ce2,
+                                       be16_to_cpu(ip[i]));
                                if (!ce1)
                                        break;
                                i++;
@@ -211,7 +215,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
                                goto done;
                        }
                }
-       same:
+same:
                switch (c0) {
                case 0:
                        cc = 0x2400;
@@ -222,7 +226,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
                default:
                        cc = c0;
                }
-       done:
+done:
                res = nls->uni2char(cc, op, len);
                if (res < 0) {
                        if (res == -ENAMETOOLONG)
@@ -392,7 +396,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
                        astr1 += size;
                        len1 -= size;
 
-                       if (!decompose || !(dstr1 = decompose_unichar(c, &dsize1))) {
+                       if (decompose)
+                               dstr1 = decompose_unichar(c, &dsize1);
+                       if (!decompose || !dstr1) {
                                c1 = c;
                                dstr1 = &c1;
                                dsize1 = 1;
@@ -404,7 +410,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
                        astr2 += size;
                        len2 -= size;
 
-                       if (!decompose || !(dstr2 = decompose_unichar(c, &dsize2))) {
+                       if (decompose)
+                               dstr2 = decompose_unichar(c, &dsize2);
+                       if (!decompose || !dstr2) {
                                c2 = c;
                                dstr2 = &c2;
                                dsize2 = 1;
index 8972c20b3216941a88eb3deffa591d89ea3c114a..196231794f646de0ead6b1e3d6cfc5d29c7ce54d 100644 (file)
@@ -24,6 +24,40 @@ struct hfsplus_wd {
        u16 embed_count;
 };
 
+static void hfsplus_end_io_sync(struct bio *bio, int err)
+{
+       if (err)
+               clear_bit(BIO_UPTODATE, &bio->bi_flags);
+       complete(bio->bi_private);
+}
+
+int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
+               void *data, int rw)
+{
+       DECLARE_COMPLETION_ONSTACK(wait);
+       struct bio *bio;
+
+       bio = bio_alloc(GFP_NOIO, 1);
+       bio->bi_sector = sector;
+       bio->bi_bdev = bdev;
+       bio->bi_end_io = hfsplus_end_io_sync;
+       bio->bi_private = &wait;
+
+       /*
+        * We always submit one sector at a time, so bio_add_page must not fail.
+        */
+       if (bio_add_page(bio, virt_to_page(data), HFSPLUS_SECTOR_SIZE,
+                        offset_in_page(data)) != HFSPLUS_SECTOR_SIZE)
+               BUG();
+
+       submit_bio(rw, bio);
+       wait_for_completion(&wait);
+
+       if (!bio_flagged(bio, BIO_UPTODATE))
+               return -EIO;
+       return 0;
+}
+
 static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
 {
        u32 extent;
@@ -40,12 +74,14 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
           !(attrib & HFSP_WRAP_ATTRIB_SPARED))
                return 0;
 
-       wd->ablk_size = be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE));
+       wd->ablk_size =
+               be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE));
        if (wd->ablk_size < HFSPLUS_SECTOR_SIZE)
                return 0;
        if (wd->ablk_size % HFSPLUS_SECTOR_SIZE)
                return 0;
-       wd->ablk_start = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
+       wd->ablk_start =
+               be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
 
        extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT);
        wd->embed_start = (extent >> 16) & 0xFFFF;
@@ -68,7 +104,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
        if (HFSPLUS_SB(sb)->session >= 0) {
                te.cdte_track = HFSPLUS_SB(sb)->session;
                te.cdte_format = CDROM_LBA;
-               res = ioctl_by_bdev(sb->s_bdev, CDROMREADTOCENTRY, (unsigned long)&te);
+               res = ioctl_by_bdev(sb->s_bdev,
+                       CDROMREADTOCENTRY, (unsigned long)&te);
                if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) {
                        *start = (sector_t)te.cdte_addr.lba << 2;
                        return 0;
@@ -77,7 +114,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
                return -EINVAL;
        }
        ms_info.addr_format = CDROM_LBA;
-       res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION, (unsigned long)&ms_info);
+       res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION,
+               (unsigned long)&ms_info);
        if (!res && ms_info.xa_flag)
                *start = (sector_t)ms_info.addr.lba << 2;
        return 0;
@@ -88,100 +126,112 @@ static int hfsplus_get_last_session(struct super_block *sb,
 int hfsplus_read_wrapper(struct super_block *sb)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
-       struct buffer_head *bh;
-       struct hfsplus_vh *vhdr;
        struct hfsplus_wd wd;
        sector_t part_start, part_size;
        u32 blocksize;
+       int error = 0;
 
+       error = -EINVAL;
        blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE);
        if (!blocksize)
-               return -EINVAL;
+               goto out;
 
        if (hfsplus_get_last_session(sb, &part_start, &part_size))
-               return -EINVAL;
+               goto out;
        if ((u64)part_start + part_size > 0x100000000ULL) {
                pr_err("hfs: volumes larger than 2TB are not supported yet\n");
-               return -EINVAL;
+               goto out;
        }
-       while (1) {
-               bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
-               if (!bh)
-                       return -EIO;
-
-               if (vhdr->signature == cpu_to_be16(HFSP_WRAP_MAGIC)) {
-                       if (!hfsplus_read_mdb(vhdr, &wd))
-                               goto error;
-                       wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
-                       part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
-                       part_size = wd.embed_count * wd.ablk_size;
-                       brelse(bh);
-                       bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
-                       if (!bh)
-                               return -EIO;
-               }
-               if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
-                       break;
-               if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) {
-                       set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
-                       break;
-               }
-               brelse(bh);
 
-               /* check for a partition block
+       error = -ENOMEM;
+       sbi->s_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
+       if (!sbi->s_vhdr)
+               goto out;
+       sbi->s_backup_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
+       if (!sbi->s_backup_vhdr)
+               goto out_free_vhdr;
+
+reread:
+       error = hfsplus_submit_bio(sb->s_bdev,
+                                  part_start + HFSPLUS_VOLHEAD_SECTOR,
+                                  sbi->s_vhdr, READ);
+       if (error)
+               goto out_free_backup_vhdr;
+
+       error = -EINVAL;
+       switch (sbi->s_vhdr->signature) {
+       case cpu_to_be16(HFSPLUS_VOLHEAD_SIGX):
+               set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
+               /*FALLTHRU*/
+       case cpu_to_be16(HFSPLUS_VOLHEAD_SIG):
+               break;
+       case cpu_to_be16(HFSP_WRAP_MAGIC):
+               if (!hfsplus_read_mdb(sbi->s_vhdr, &wd))
+                       goto out;
+               wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
+               part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
+               part_size = wd.embed_count * wd.ablk_size;
+               goto reread;
+       default:
+               /*
+                * Check for a partition block.
+                *
                 * (should do this only for cdrom/loop though)
                 */
                if (hfs_part_find(sb, &part_start, &part_size))
-                       return -EINVAL;
+                       goto out;
+               goto reread;
+       }
+
+       error = hfsplus_submit_bio(sb->s_bdev,
+                                  part_start + part_size - 2,
+                                  sbi->s_backup_vhdr, READ);
+       if (error)
+               goto out_free_backup_vhdr;
+
+       error = -EINVAL;
+       if (sbi->s_backup_vhdr->signature != sbi->s_vhdr->signature) {
+               printk(KERN_WARNING
+                       "hfs: invalid secondary volume header\n");
+               goto out_free_backup_vhdr;
        }
 
-       blocksize = be32_to_cpu(vhdr->blocksize);
-       brelse(bh);
+       blocksize = be32_to_cpu(sbi->s_vhdr->blocksize);
 
-       /* block size must be at least as large as a sector
-        * and a multiple of 2
+       /*
+        * Block size must be at least as large as a sector and a multiple of 2.
         */
-       if (blocksize < HFSPLUS_SECTOR_SIZE ||
-           ((blocksize - 1) & blocksize))
-               return -EINVAL;
+       if (blocksize < HFSPLUS_SECTOR_SIZE || ((blocksize - 1) & blocksize))
+               goto out_free_backup_vhdr;
        sbi->alloc_blksz = blocksize;
        sbi->alloc_blksz_shift = 0;
        while ((blocksize >>= 1) != 0)
                sbi->alloc_blksz_shift++;
        blocksize = min(sbi->alloc_blksz, (u32)PAGE_SIZE);
 
-       /* align block size to block offset */
+       /*
+        * Align block size to block offset.
+        */
        while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1))
                blocksize >>= 1;
 
        if (sb_set_blocksize(sb, blocksize) != blocksize) {
-               printk(KERN_ERR "hfs: unable to set blocksize to %u!\n", blocksize);
-               return -EINVAL;
+               printk(KERN_ERR "hfs: unable to set blocksize to %u!\n",
+                       blocksize);
+               goto out_free_backup_vhdr;
        }
 
        sbi->blockoffset =
                part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT);
+       sbi->part_start = part_start;
        sbi->sect_count = part_size;
        sbi->fs_shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
-
-       bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
-       if (!bh)
-               return -EIO;
-
-       /* should still be the same... */
-       if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
-               if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX))
-                       goto error;
-       } else {
-               if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
-                       goto error;
-       }
-
-       sbi->s_vhbh = bh;
-       sbi->s_vhdr = vhdr;
-
        return 0;
- error:
-       brelse(bh);
-       return -EINVAL;
+
+out_free_backup_vhdr:
+       kfree(sbi->s_backup_vhdr);
+out_free_vhdr:
+       kfree(sbi->s_vhdr);
+out:
+       return error;
 }
index 19433cdba0118d9a4bfda3dfbd654279e6928409..24ece10470b67b751f2cd7a48ed3b8ff2a1e2979 100644 (file)
@@ -202,7 +202,7 @@ static int acl_permission_check(struct inode *inode, int mask, unsigned int flag
  * @inode:     inode to check access rights for
  * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
  * @check_acl: optional callback to check for Posix ACLs
- * @flags      IPERM_FLAG_ flags.
+ * @flags:     IPERM_FLAG_ flags.
  *
  * Used to check for read/write/execute permissions on a file.
  * We use "fsuid" for this, letting us set arbitrary permissions
@@ -407,7 +407,7 @@ void path_put_long(struct path *path)
 /**
  * nameidata_drop_rcu - drop this nameidata out of rcu-walk
  * @nd: nameidata pathwalk data to drop
- * @Returns: 0 on success, -ECHLID on failure
+ * Returns: 0 on success, -ECHILD on failure
  *
  * Path walking has 2 modes, rcu-walk and ref-walk (see
  * Documentation/filesystems/path-lookup.txt). __drop_rcu* functions attempt
@@ -468,7 +468,7 @@ static inline int nameidata_drop_rcu_maybe(struct nameidata *nd)
  * nameidata_dentry_drop_rcu - drop nameidata and dentry out of rcu-walk
  * @nd: nameidata pathwalk data to drop
  * @dentry: dentry to drop
- * @Returns: 0 on success, -ECHLID on failure
+ * Returns: 0 on success, -ECHILD on failure
  *
  * nameidata_dentry_drop_rcu attempts to drop the current nd->path and nd->root,
  * and dentry into ref-walk. @dentry must be a path found by a do_lookup call on
@@ -530,7 +530,7 @@ static inline int nameidata_dentry_drop_rcu_maybe(struct nameidata *nd, struct d
 /**
  * nameidata_drop_rcu_last - drop nameidata ending path walk out of rcu-walk
  * @nd: nameidata pathwalk data to drop
- * @Returns: 0 on success, -ECHLID on failure
+ * Returns: 0 on success, -ECHILD on failure
  *
  * nameidata_drop_rcu_last attempts to drop the current nd->path into ref-walk.
  * nd->path should be the final element of the lookup, so nd->root is discarded.
index 9531c052d7a487a0b46d347ffed016ea06bdcd50..9b39a5dd413140c6624de8680f07193227a6173d 100644 (file)
@@ -317,7 +317,12 @@ static void ncp_stop_tasks(struct ncp_server *server) {
        sk->sk_write_space  = server->write_space;
        release_sock(sk);
        del_timer_sync(&server->timeout_tm);
-       flush_scheduled_work();
+
+       flush_work_sync(&server->rcv.tq);
+       if (sk->sk_socket->type == SOCK_STREAM)
+               flush_work_sync(&server->tx.tq);
+       else
+               flush_work_sync(&server->timeout_tq);
 }
 
 static int  ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
index 116cab970e0f3d737c8377bde9c3d97192568c71..fbd18c3074bbb54aad024e08024b31fac9fc7d53 100644 (file)
@@ -4336,7 +4336,7 @@ __nfs4_state_shutdown(void)
 void
 nfs4_state_shutdown(void)
 {
-       cancel_rearming_delayed_workqueue(laundry_wq, &laundromat_work);
+       cancel_delayed_work_sync(&laundromat_work);
        destroy_workqueue(laundry_wq);
        locks_end_grace(&nfsd4_manager);
        nfs4_lock_state();
index 8b782b062baa6e54cb37f5a53c91d9e3c98019cf..3ee67c67cc52ee5d6d0711023bb2c2ad43c1e32c 100644 (file)
 
 struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap)
 {
-       return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode));
+       return NILFS_I_NILFS(bmap->b_inode)->ns_dat;
+}
+
+static int nilfs_bmap_convert_error(struct nilfs_bmap *bmap,
+                                    const char *fname, int err)
+{
+       struct inode *inode = bmap->b_inode;
+
+       if (err == -EINVAL) {
+               nilfs_error(inode->i_sb, fname,
+                           "broken bmap (inode number=%lu)\n", inode->i_ino);
+               err = -EIO;
+       }
+       return err;
 }
 
 /**
@@ -66,8 +79,10 @@ int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level,
 
        down_read(&bmap->b_sem);
        ret = bmap->b_ops->bop_lookup(bmap, key, level, ptrp);
-       if (ret < 0)
+       if (ret < 0) {
+               ret = nilfs_bmap_convert_error(bmap, __func__, ret);
                goto out;
+       }
        if (NILFS_BMAP_USE_VBN(bmap)) {
                ret = nilfs_dat_translate(nilfs_bmap_get_dat(bmap), *ptrp,
                                          &blocknr);
@@ -88,7 +103,8 @@ int nilfs_bmap_lookup_contig(struct nilfs_bmap *bmap, __u64 key, __u64 *ptrp,
        down_read(&bmap->b_sem);
        ret = bmap->b_ops->bop_lookup_contig(bmap, key, ptrp, maxblocks);
        up_read(&bmap->b_sem);
-       return ret;
+
+       return nilfs_bmap_convert_error(bmap, __func__, ret);
 }
 
 static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
@@ -144,7 +160,8 @@ int nilfs_bmap_insert(struct nilfs_bmap *bmap,
        down_write(&bmap->b_sem);
        ret = nilfs_bmap_do_insert(bmap, key, rec);
        up_write(&bmap->b_sem);
-       return ret;
+
+       return nilfs_bmap_convert_error(bmap, __func__, ret);
 }
 
 static int nilfs_bmap_do_delete(struct nilfs_bmap *bmap, __u64 key)
@@ -180,9 +197,12 @@ int nilfs_bmap_last_key(struct nilfs_bmap *bmap, unsigned long *key)
 
        down_read(&bmap->b_sem);
        ret = bmap->b_ops->bop_last_key(bmap, &lastkey);
-       if (!ret)
-               *key = lastkey;
        up_read(&bmap->b_sem);
+
+       if (ret < 0)
+               ret = nilfs_bmap_convert_error(bmap, __func__, ret);
+       else
+               *key = lastkey;
        return ret;
 }
 
@@ -210,7 +230,8 @@ int nilfs_bmap_delete(struct nilfs_bmap *bmap, unsigned long key)
        down_write(&bmap->b_sem);
        ret = nilfs_bmap_do_delete(bmap, key);
        up_write(&bmap->b_sem);
-       return ret;
+
+       return nilfs_bmap_convert_error(bmap, __func__, ret);
 }
 
 static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, unsigned long key)
@@ -261,7 +282,8 @@ int nilfs_bmap_truncate(struct nilfs_bmap *bmap, unsigned long key)
        down_write(&bmap->b_sem);
        ret = nilfs_bmap_do_truncate(bmap, key);
        up_write(&bmap->b_sem);
-       return ret;
+
+       return nilfs_bmap_convert_error(bmap, __func__, ret);
 }
 
 /**
@@ -300,7 +322,8 @@ int nilfs_bmap_propagate(struct nilfs_bmap *bmap, struct buffer_head *bh)
        down_write(&bmap->b_sem);
        ret = bmap->b_ops->bop_propagate(bmap, bh);
        up_write(&bmap->b_sem);
-       return ret;
+
+       return nilfs_bmap_convert_error(bmap, __func__, ret);
 }
 
 /**
@@ -344,7 +367,8 @@ int nilfs_bmap_assign(struct nilfs_bmap *bmap,
        down_write(&bmap->b_sem);
        ret = bmap->b_ops->bop_assign(bmap, bh, blocknr, binfo);
        up_write(&bmap->b_sem);
-       return ret;
+
+       return nilfs_bmap_convert_error(bmap, __func__, ret);
 }
 
 /**
@@ -373,7 +397,8 @@ int nilfs_bmap_mark(struct nilfs_bmap *bmap, __u64 key, int level)
        down_write(&bmap->b_sem);
        ret = bmap->b_ops->bop_mark(bmap, key, level);
        up_write(&bmap->b_sem);
-       return ret;
+
+       return nilfs_bmap_convert_error(bmap, __func__, ret);
 }
 
 /**
index 5115814cb74503bd4d34502817e9713a6f90541d..388e9e8f5286f737970ccefa36e919556235e4bf 100644 (file)
@@ -104,8 +104,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
        if (pblocknr == 0) {
                pblocknr = blocknr;
                if (inode->i_ino != NILFS_DAT_INO) {
-                       struct inode *dat =
-                               nilfs_dat_inode(NILFS_I_NILFS(inode));
+                       struct inode *dat = NILFS_I_NILFS(inode)->ns_dat;
 
                        /* blocknr is a virtual block number */
                        err = nilfs_dat_translate(dat, blocknr, &pblocknr);
index cb003c8ee1f6d9f839bd78f2a3c182086d629645..9d45773b79e63f9d7be433ca604caef7fc518cea 100644 (file)
@@ -91,7 +91,6 @@ static void nilfs_commit_chunk(struct page *page,
                               unsigned from, unsigned to)
 {
        struct inode *dir = mapping->host;
-       struct nilfs_sb_info *sbi = NILFS_SB(dir->i_sb);
        loff_t pos = page_offset(page) + from;
        unsigned len = to - from;
        unsigned nr_dirty, copied;
@@ -103,7 +102,7 @@ static void nilfs_commit_chunk(struct page *page,
                i_size_write(dir, pos + copied);
        if (IS_DIRSYNC(dir))
                nilfs_set_transaction_flag(NILFS_TI_SYNC);
-       err = nilfs_set_file_dirty(sbi, dir, nr_dirty);
+       err = nilfs_set_file_dirty(dir, nr_dirty);
        WARN_ON(err); /* do not happen */
        unlock_page(page);
 }
index c9a30d7ff6fc340f1b8df37ba03e6e5441f6a5af..2f560c9fb808192cdddad3277c345e04440b1fb6 100644 (file)
@@ -155,6 +155,7 @@ const struct inode_operations nilfs_file_inode_operations = {
        .truncate       = nilfs_truncate,
        .setattr        = nilfs_setattr,
        .permission     = nilfs_permission,
+       .fiemap         = nilfs_fiemap,
 };
 
 /* end of file */
index 9f8a2da67f901f666a0180a21d0bd938a6506af8..bfc73d3a30ed438ef4900fd580c0ad0b0d2c2861 100644 (file)
@@ -149,14 +149,9 @@ int nilfs_ifile_get_inode_block(struct inode *ifile, ino_t ino,
        }
 
        err = nilfs_palloc_get_entry_block(ifile, ino, 0, out_bh);
-       if (unlikely(err)) {
-               if (err == -EINVAL)
-                       nilfs_error(sb, __func__, "ifile is broken");
-               else
-                       nilfs_warning(sb, __func__,
-                                     "unable to read inode: %lu",
-                                     (unsigned long) ino);
-       }
+       if (unlikely(err))
+               nilfs_warning(sb, __func__, "unable to read inode: %lu",
+                             (unsigned long) ino);
        return err;
 }
 
index 77b48c8fab17c31015cf7a5433ef794f524b3ee8..2fd440d8d6b8d9b2b469c2aaec757bca05a9ac58 100644 (file)
@@ -58,7 +58,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
        struct nilfs_inode_info *ii = NILFS_I(inode);
        __u64 blknum = 0;
        int err = 0, ret;
-       struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode));
+       struct inode *dat = NILFS_I_NILFS(inode)->ns_dat;
        unsigned maxblocks = bh_result->b_size >> inode->i_blkbits;
 
        down_read(&NILFS_MDT(dat)->mi_sem);
@@ -96,11 +96,6 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
                                       inode->i_ino,
                                       (unsigned long long)blkoff);
                                err = 0;
-                       } else if (err == -EINVAL) {
-                               nilfs_error(inode->i_sb, __func__,
-                                           "broken bmap (inode=%lu)\n",
-                                           inode->i_ino);
-                               err = -EIO;
                        }
                        nilfs_transaction_abort(inode->i_sb);
                        goto out;
@@ -109,6 +104,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
                nilfs_transaction_commit(inode->i_sb); /* never fails */
                /* Error handling should be detailed */
                set_buffer_new(bh_result);
+               set_buffer_delay(bh_result);
                map_bh(bh_result, inode->i_sb, 0); /* dbn must be changed
                                                      to proper value */
        } else if (ret == -ENOENT) {
@@ -185,10 +181,9 @@ static int nilfs_set_page_dirty(struct page *page)
 
        if (ret) {
                struct inode *inode = page->mapping->host;
-               struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
                unsigned nr_dirty = 1 << (PAGE_SHIFT - inode->i_blkbits);
 
-               nilfs_set_file_dirty(sbi, inode, nr_dirty);
+               nilfs_set_file_dirty(inode, nr_dirty);
        }
        return ret;
 }
@@ -229,7 +224,7 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping,
                                                  start + copied);
        copied = generic_write_end(file, mapping, pos, len, copied, page,
                                   fsdata);
-       nilfs_set_file_dirty(NILFS_SB(inode->i_sb), inode, nr_dirty);
+       nilfs_set_file_dirty(inode, nr_dirty);
        err = nilfs_transaction_commit(inode->i_sb);
        return err ? : copied;
 }
@@ -425,13 +420,12 @@ static int __nilfs_read_inode(struct super_block *sb,
                              struct nilfs_root *root, unsigned long ino,
                              struct inode *inode)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct inode *dat = nilfs_dat_inode(sbi->s_nilfs);
+       struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs;
        struct buffer_head *bh;
        struct nilfs_inode *raw_inode;
        int err;
 
-       down_read(&NILFS_MDT(dat)->mi_sem);     /* XXX */
+       down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
        err = nilfs_ifile_get_inode_block(root->ifile, ino, &bh);
        if (unlikely(err))
                goto bad_inode;
@@ -461,7 +455,7 @@ static int __nilfs_read_inode(struct super_block *sb,
        }
        nilfs_ifile_unmap_inode(root->ifile, ino, bh);
        brelse(bh);
-       up_read(&NILFS_MDT(dat)->mi_sem);       /* XXX */
+       up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
        nilfs_set_inode_flags(inode);
        return 0;
 
@@ -470,7 +464,7 @@ static int __nilfs_read_inode(struct super_block *sb,
        brelse(bh);
 
  bad_inode:
-       up_read(&NILFS_MDT(dat)->mi_sem);       /* XXX */
+       up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
        return err;
 }
 
@@ -629,7 +623,7 @@ static void nilfs_truncate_bmap(struct nilfs_inode_info *ii,
 
        if (!test_bit(NILFS_I_BMAP, &ii->i_state))
                return;
- repeat:
+repeat:
        ret = nilfs_bmap_last_key(ii->i_bmap, &b);
        if (ret == -ENOENT)
                return;
@@ -646,14 +640,10 @@ static void nilfs_truncate_bmap(struct nilfs_inode_info *ii,
                     nilfs_bmap_truncate(ii->i_bmap, b) == 0))
                goto repeat;
 
- failed:
-       if (ret == -EINVAL)
-               nilfs_error(ii->vfs_inode.i_sb, __func__,
-                           "bmap is broken (ino=%lu)", ii->vfs_inode.i_ino);
-       else
-               nilfs_warning(ii->vfs_inode.i_sb, __func__,
-                             "failed to truncate bmap (ino=%lu, err=%d)",
-                             ii->vfs_inode.i_ino, ret);
+failed:
+       nilfs_warning(ii->vfs_inode.i_sb, __func__,
+                     "failed to truncate bmap (ino=%lu, err=%d)",
+                     ii->vfs_inode.i_ino, ret);
 }
 
 void nilfs_truncate(struct inode *inode)
@@ -682,7 +672,7 @@ void nilfs_truncate(struct inode *inode)
                nilfs_set_transaction_flag(NILFS_TI_SYNC);
 
        nilfs_mark_inode_dirty(inode);
-       nilfs_set_file_dirty(NILFS_SB(sb), inode, 0);
+       nilfs_set_file_dirty(inode, 0);
        nilfs_transaction_commit(sb);
        /* May construct a logical segment and may fail in sync mode.
           But truncate has no return value. */
@@ -800,9 +790,9 @@ int nilfs_permission(struct inode *inode, int mask, unsigned int flags)
        return generic_permission(inode, mask, flags, NULL);
 }
 
-int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode,
-                          struct buffer_head **pbh)
+int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh)
 {
+       struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
        struct nilfs_inode_info *ii = NILFS_I(inode);
        int err;
 
@@ -843,9 +833,9 @@ int nilfs_inode_dirty(struct inode *inode)
        return ret;
 }
 
-int nilfs_set_file_dirty(struct nilfs_sb_info *sbi, struct inode *inode,
-                        unsigned nr_dirty)
+int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty)
 {
+       struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
        struct nilfs_inode_info *ii = NILFS_I(inode);
 
        atomic_add(nr_dirty, &sbi->s_nilfs->ns_ndirtyblks);
@@ -878,11 +868,10 @@ int nilfs_set_file_dirty(struct nilfs_sb_info *sbi, struct inode *inode,
 
 int nilfs_mark_inode_dirty(struct inode *inode)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
        struct buffer_head *ibh;
        int err;
 
-       err = nilfs_load_inode_block(sbi, inode, &ibh);
+       err = nilfs_load_inode_block(inode, &ibh);
        if (unlikely(err)) {
                nilfs_warning(inode->i_sb, __func__,
                              "failed to reget inode block.\n");
@@ -924,3 +913,134 @@ void nilfs_dirty_inode(struct inode *inode)
        nilfs_mark_inode_dirty(inode);
        nilfs_transaction_commit(inode->i_sb); /* never fails */
 }
+
+int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+                __u64 start, __u64 len)
+{
+       struct the_nilfs *nilfs = NILFS_I_NILFS(inode);
+       __u64 logical = 0, phys = 0, size = 0;
+       __u32 flags = 0;
+       loff_t isize;
+       sector_t blkoff, end_blkoff;
+       sector_t delalloc_blkoff;
+       unsigned long delalloc_blklen;
+       unsigned int blkbits = inode->i_blkbits;
+       int ret, n;
+
+       ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
+       if (ret)
+               return ret;
+
+       mutex_lock(&inode->i_mutex);
+
+       isize = i_size_read(inode);
+
+       blkoff = start >> blkbits;
+       end_blkoff = (start + len - 1) >> blkbits;
+
+       delalloc_blklen = nilfs_find_uncommitted_extent(inode, blkoff,
+                                                       &delalloc_blkoff);
+
+       do {
+               __u64 blkphy;
+               unsigned int maxblocks;
+
+               if (delalloc_blklen && blkoff == delalloc_blkoff) {
+                       if (size) {
+                               /* End of the current extent */
+                               ret = fiemap_fill_next_extent(
+                                       fieinfo, logical, phys, size, flags);
+                               if (ret)
+                                       break;
+                       }
+                       if (blkoff > end_blkoff)
+                               break;
+
+                       flags = FIEMAP_EXTENT_MERGED | FIEMAP_EXTENT_DELALLOC;
+                       logical = blkoff << blkbits;
+                       phys = 0;
+                       size = delalloc_blklen << blkbits;
+
+                       blkoff = delalloc_blkoff + delalloc_blklen;
+                       delalloc_blklen = nilfs_find_uncommitted_extent(
+                               inode, blkoff, &delalloc_blkoff);
+                       continue;
+               }
+
+               /*
+                * Limit the number of blocks that we look up so as
+                * not to get into the next delayed allocation extent.
+                */
+               maxblocks = INT_MAX;
+               if (delalloc_blklen)
+                       maxblocks = min_t(sector_t, delalloc_blkoff - blkoff,
+                                         maxblocks);
+               blkphy = 0;
+
+               down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
+               n = nilfs_bmap_lookup_contig(
+                       NILFS_I(inode)->i_bmap, blkoff, &blkphy, maxblocks);
+               up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
+
+               if (n < 0) {
+                       int past_eof;
+
+                       if (unlikely(n != -ENOENT))
+                               break; /* error */
+
+                       /* HOLE */
+                       blkoff++;
+                       past_eof = ((blkoff << blkbits) >= isize);
+
+                       if (size) {
+                               /* End of the current extent */
+
+                               if (past_eof)
+                                       flags |= FIEMAP_EXTENT_LAST;
+
+                               ret = fiemap_fill_next_extent(
+                                       fieinfo, logical, phys, size, flags);
+                               if (ret)
+                                       break;
+                               size = 0;
+                       }
+                       if (blkoff > end_blkoff || past_eof)
+                               break;
+               } else {
+                       if (size) {
+                               if (phys && blkphy << blkbits == phys + size) {
+                                       /* The current extent goes on */
+                                       size += n << blkbits;
+                               } else {
+                                       /* Terminate the current extent */
+                                       ret = fiemap_fill_next_extent(
+                                               fieinfo, logical, phys, size,
+                                               flags);
+                                       if (ret || blkoff > end_blkoff)
+                                               break;
+
+                                       /* Start another extent */
+                                       flags = FIEMAP_EXTENT_MERGED;
+                                       logical = blkoff << blkbits;
+                                       phys = blkphy << blkbits;
+                                       size = n << blkbits;
+                               }
+                       } else {
+                               /* Start a new extent */
+                               flags = FIEMAP_EXTENT_MERGED;
+                               logical = blkoff << blkbits;
+                               phys = blkphy << blkbits;
+                               size = n << blkbits;
+                       }
+                       blkoff += n;
+               }
+               cond_resched();
+       } while (true);
+
+       /* If ret is 1 then we just hit the end of the extent array */
+       if (ret == 1)
+               ret = 0;
+
+       mutex_unlock(&inode->i_mutex);
+       return ret;
+}
index b185e937a335471ec224314909a959684f56d174..496738963fdbd029aa2a39723442020c5c4d9e93 100644 (file)
@@ -233,7 +233,7 @@ nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
        int ret;
 
        down_read(&nilfs->ns_segctor_sem);
-       ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, size, nmembs);
+       ret = nilfs_dat_get_vinfo(nilfs->ns_dat, buf, size, nmembs);
        up_read(&nilfs->ns_segctor_sem);
        return ret;
 }
@@ -242,8 +242,7 @@ static ssize_t
 nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags,
                          void *buf, size_t size, size_t nmembs)
 {
-       struct inode *dat = nilfs_dat_inode(nilfs);
-       struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
+       struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap;
        struct nilfs_bdesc *bdescs = buf;
        int ret, i;
 
@@ -421,7 +420,7 @@ static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs,
        size_t nmembs = argv->v_nmembs;
        int ret;
 
-       ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs);
+       ret = nilfs_dat_freev(nilfs->ns_dat, buf, nmembs);
 
        return (ret < 0) ? ret : nmembs;
 }
@@ -430,8 +429,7 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
                                         struct nilfs_argv *argv, void *buf)
 {
        size_t nmembs = argv->v_nmembs;
-       struct inode *dat = nilfs_dat_inode(nilfs);
-       struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
+       struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap;
        struct nilfs_bdesc *bdescs = buf;
        int ret, i;
 
@@ -450,7 +448,7 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
                        /* skip dead block */
                        continue;
                if (bdescs[i].bd_level == 0) {
-                       ret = nilfs_mdt_mark_block_dirty(dat,
+                       ret = nilfs_mdt_mark_block_dirty(nilfs->ns_dat,
                                                         bdescs[i].bd_offset);
                        if (ret < 0) {
                                WARN_ON(ret == -ENOENT);
index 39a5b84e2c9fbbac846ec50133b496798220373a..6a0e2a189f60650b3399f4b9d3732ac6037f791f 100644 (file)
@@ -237,8 +237,6 @@ static int nilfs_mdt_read_block(struct inode *inode, unsigned long block,
  *
  * %-ENOENT - the specified block does not exist (hole block)
  *
- * %-EINVAL - bmap is broken. (the caller should call nilfs_error())
- *
  * %-EROFS - Read only filesystem (for create mode)
  */
 int nilfs_mdt_get_block(struct inode *inode, unsigned long blkoff, int create,
@@ -273,8 +271,6 @@ int nilfs_mdt_get_block(struct inode *inode, unsigned long blkoff, int create,
  * %-ENOMEM - Insufficient memory available.
  *
  * %-EIO - I/O error
- *
- * %-EINVAL - bmap is broken. (the caller should call nilfs_error())
  */
 int nilfs_mdt_delete_block(struct inode *inode, unsigned long block)
 {
@@ -350,8 +346,6 @@ int nilfs_mdt_forget_block(struct inode *inode, unsigned long block)
  * %-EIO - I/O error
  *
  * %-ENOENT - the specified block does not exist (hole block)
- *
- * %-EINVAL - bmap is broken. (the caller should call nilfs_error())
  */
 int nilfs_mdt_mark_block_dirty(struct inode *inode, unsigned long block)
 {
@@ -499,31 +493,29 @@ int nilfs_mdt_freeze_buffer(struct inode *inode, struct buffer_head *bh)
        struct buffer_head *bh_frozen;
        struct page *page;
        int blkbits = inode->i_blkbits;
-       int ret = -ENOMEM;
 
        page = grab_cache_page(&shadow->frozen_data, bh->b_page->index);
        if (!page)
-               return ret;
+               return -ENOMEM;
 
        if (!page_has_buffers(page))
                create_empty_buffers(page, 1 << blkbits, 0);
 
        bh_frozen = nilfs_page_get_nth_block(page, bh_offset(bh) >> blkbits);
-       if (bh_frozen) {
-               if (!buffer_uptodate(bh_frozen))
-                       nilfs_copy_buffer(bh_frozen, bh);
-               if (list_empty(&bh_frozen->b_assoc_buffers)) {
-                       list_add_tail(&bh_frozen->b_assoc_buffers,
-                                     &shadow->frozen_buffers);
-                       set_buffer_nilfs_redirected(bh);
-               } else {
-                       brelse(bh_frozen); /* already frozen */
-               }
-               ret = 0;
+
+       if (!buffer_uptodate(bh_frozen))
+               nilfs_copy_buffer(bh_frozen, bh);
+       if (list_empty(&bh_frozen->b_assoc_buffers)) {
+               list_add_tail(&bh_frozen->b_assoc_buffers,
+                             &shadow->frozen_buffers);
+               set_buffer_nilfs_redirected(bh);
+       } else {
+               brelse(bh_frozen); /* already frozen */
        }
+
        unlock_page(page);
        page_cache_release(page);
-       return ret;
+       return 0;
 }
 
 struct buffer_head *
index 6e9557ecf161fd664a0715d9a3b8e0f3e34501dd..98034271cd02e06194e28701aa63c8086fe0ed7e 100644 (file)
@@ -577,6 +577,7 @@ const struct inode_operations nilfs_dir_inode_operations = {
        .rename         = nilfs_rename,
        .setattr        = nilfs_setattr,
        .permission     = nilfs_permission,
+       .fiemap         = nilfs_fiemap,
 };
 
 const struct inode_operations nilfs_special_inode_operations = {
index 0ca98823db5934400f5671dabd367ececc91cdc2..777e8fd043049dcfb53def4e5cc78ec50a9ec991 100644 (file)
@@ -190,11 +190,6 @@ static inline int nilfs_doing_construction(void)
        return nilfs_test_transaction_flag(NILFS_TI_WRITER);
 }
 
-static inline struct inode *nilfs_dat_inode(const struct the_nilfs *nilfs)
-{
-       return nilfs->ns_dat;
-}
-
 /*
  * function prototype
  */
@@ -257,13 +252,13 @@ extern void nilfs_truncate(struct inode *);
 extern void nilfs_evict_inode(struct inode *);
 extern int nilfs_setattr(struct dentry *, struct iattr *);
 int nilfs_permission(struct inode *inode, int mask, unsigned int flags);
-extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *,
-                                 struct buffer_head **);
+int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh);
 extern int nilfs_inode_dirty(struct inode *);
-extern int nilfs_set_file_dirty(struct nilfs_sb_info *, struct inode *,
-                               unsigned);
+int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty);
 extern int nilfs_mark_inode_dirty(struct inode *);
 extern void nilfs_dirty_inode(struct inode *);
+int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+                __u64 start, __u64 len);
 
 /* super.c */
 extern struct inode *nilfs_alloc_inode(struct super_block *);
index a6c3c2e817f8b0203994cfe9d11a2526173aba27..0c432416cfefc608383dc8f7ee58d88140a26f59 100644 (file)
@@ -491,7 +491,7 @@ unsigned nilfs_page_count_clean_buffers(struct page *page,
        }
        return nc;
 }
+
 void nilfs_mapping_init_once(struct address_space *mapping)
 {
        memset(mapping, 0, sizeof(*mapping));
@@ -546,3 +546,87 @@ int __nilfs_clear_page_dirty(struct page *page)
        }
        return TestClearPageDirty(page);
 }
+
+/**
+ * nilfs_find_uncommitted_extent - find extent of uncommitted data
+ * @inode: inode
+ * @start_blk: start block offset (in)
+ * @blkoff: start offset of the found extent (out)
+ *
+ * This function searches an extent of buffers marked "delayed" which
+ * starts from a block offset equal to or larger than @start_blk.  If
+ * such an extent was found, this will store the start offset in
+ * @blkoff and return its length in blocks.  Otherwise, zero is
+ * returned.
+ */
+unsigned long nilfs_find_uncommitted_extent(struct inode *inode,
+                                           sector_t start_blk,
+                                           sector_t *blkoff)
+{
+       unsigned int i;
+       pgoff_t index;
+       unsigned int nblocks_in_page;
+       unsigned long length = 0;
+       sector_t b;
+       struct pagevec pvec;
+       struct page *page;
+
+       if (inode->i_mapping->nrpages == 0)
+               return 0;
+
+       index = start_blk >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       nblocks_in_page = 1U << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+       pagevec_init(&pvec, 0);
+
+repeat:
+       pvec.nr = find_get_pages_contig(inode->i_mapping, index, PAGEVEC_SIZE,
+                                       pvec.pages);
+       if (pvec.nr == 0)
+               return length;
+
+       if (length > 0 && pvec.pages[0]->index > index)
+               goto out;
+
+       b = pvec.pages[0]->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       i = 0;
+       do {
+               page = pvec.pages[i];
+
+               lock_page(page);
+               if (page_has_buffers(page)) {
+                       struct buffer_head *bh, *head;
+
+                       bh = head = page_buffers(page);
+                       do {
+                               if (b < start_blk)
+                                       continue;
+                               if (buffer_delay(bh)) {
+                                       if (length == 0)
+                                               *blkoff = b;
+                                       length++;
+                               } else if (length > 0) {
+                                       goto out_locked;
+                               }
+                       } while (++b, bh = bh->b_this_page, bh != head);
+               } else {
+                       if (length > 0)
+                               goto out_locked;
+
+                       b += nblocks_in_page;
+               }
+               unlock_page(page);
+
+       } while (++i < pagevec_count(&pvec));
+
+       index = page->index + 1;
+       pagevec_release(&pvec);
+       cond_resched();
+       goto repeat;
+
+out_locked:
+       unlock_page(page);
+out:
+       pagevec_release(&pvec);
+       return length;
+}
index fb9e8a8a20384b5b78a6645d7b4809f0145e24d6..622df27cd89155d74a94ef786910715f9f3a11ad 100644 (file)
@@ -66,6 +66,9 @@ void nilfs_mapping_init(struct address_space *mapping,
                        struct backing_dev_info *bdi,
                        const struct address_space_operations *aops);
 unsigned nilfs_page_count_clean_buffers(struct page *, unsigned, unsigned);
+unsigned long nilfs_find_uncommitted_extent(struct inode *inode,
+                                           sector_t start_blk,
+                                           sector_t *blkoff);
 
 #define NILFS_PAGE_BUG(page, m, a...) \
        do { nilfs_page_bug(page); BUG(); } while (0)
index 5d2711c28da769d4b8a6e30daff75c6b479c46ec..3dfcd3b7d3891a030ea8dd7a01c0a51a73aea0bf 100644 (file)
@@ -535,7 +535,7 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
                if (unlikely(err))
                        goto failed_page;
 
-               err = nilfs_set_file_dirty(sbi, inode, 1);
+               err = nilfs_set_file_dirty(inode, 1);
                if (unlikely(err))
                        goto failed_page;
 
index 35a07157b980bc69823904f0c387d538ded45701..7a17715f215f791104c4ef752caeef5618c4e5c7 100644 (file)
 #include <linux/types.h>
 #include <linux/fs.h>
 
-/*
- * Mount options
- */
-struct nilfs_mount_options {
-       unsigned long mount_opt;
-       __u64 snapshot_cno;
-};
-
 struct the_nilfs;
 struct nilfs_sc_info;
 
index 687d090cea341fea2f0cf88ac9b4b41e36dcf957..55ebae5c7f39f58d4065850b9fabebb66a93b0cf 100644 (file)
@@ -504,17 +504,6 @@ static int nilfs_segctor_add_file_block(struct nilfs_sc_info *sci,
        return err;
 }
 
-static int nilfs_handle_bmap_error(int err, const char *fname,
-                                  struct inode *inode, struct super_block *sb)
-{
-       if (err == -EINVAL) {
-               nilfs_error(sb, fname, "broken bmap (inode=%lu)\n",
-                           inode->i_ino);
-               err = -EIO;
-       }
-       return err;
-}
-
 /*
  * Callback functions that enumerate, mark, and collect dirty blocks
  */
@@ -524,9 +513,8 @@ static int nilfs_collect_file_data(struct nilfs_sc_info *sci,
        int err;
 
        err = nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh);
-       if (unlikely(err < 0))
-               return nilfs_handle_bmap_error(err, __func__, inode,
-                                              sci->sc_super);
+       if (err < 0)
+               return err;
 
        err = nilfs_segctor_add_file_block(sci, bh, inode,
                                           sizeof(struct nilfs_binfo_v));
@@ -539,13 +527,7 @@ static int nilfs_collect_file_node(struct nilfs_sc_info *sci,
                                   struct buffer_head *bh,
                                   struct inode *inode)
 {
-       int err;
-
-       err = nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh);
-       if (unlikely(err < 0))
-               return nilfs_handle_bmap_error(err, __func__, inode,
-                                              sci->sc_super);
-       return 0;
+       return nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh);
 }
 
 static int nilfs_collect_file_bmap(struct nilfs_sc_info *sci,
@@ -588,9 +570,8 @@ static int nilfs_collect_dat_data(struct nilfs_sc_info *sci,
        int err;
 
        err = nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh);
-       if (unlikely(err < 0))
-               return nilfs_handle_bmap_error(err, __func__, inode,
-                                              sci->sc_super);
+       if (err < 0)
+               return err;
 
        err = nilfs_segctor_add_file_block(sci, bh, inode, sizeof(__le64));
        if (!err)
@@ -776,9 +757,8 @@ static int nilfs_test_metadata_dirty(struct the_nilfs *nilfs,
                ret++;
        if (nilfs_mdt_fetch_dirty(nilfs->ns_sufile))
                ret++;
-       if (ret || nilfs_doing_gc())
-               if (nilfs_mdt_fetch_dirty(nilfs_dat_inode(nilfs)))
-                       ret++;
+       if ((ret || nilfs_doing_gc()) && nilfs_mdt_fetch_dirty(nilfs->ns_dat))
+               ret++;
        return ret;
 }
 
@@ -814,7 +794,7 @@ static void nilfs_segctor_clear_metadata_dirty(struct nilfs_sc_info *sci)
        nilfs_mdt_clear_dirty(sci->sc_root->ifile);
        nilfs_mdt_clear_dirty(nilfs->ns_cpfile);
        nilfs_mdt_clear_dirty(nilfs->ns_sufile);
-       nilfs_mdt_clear_dirty(nilfs_dat_inode(nilfs));
+       nilfs_mdt_clear_dirty(nilfs->ns_dat);
 }
 
 static int nilfs_segctor_create_checkpoint(struct nilfs_sc_info *sci)
@@ -923,7 +903,7 @@ static void nilfs_segctor_fill_in_super_root(struct nilfs_sc_info *sci,
                              nilfs->ns_nongc_ctime : sci->sc_seg_ctime);
        raw_sr->sr_flags = 0;
 
-       nilfs_write_inode_common(nilfs_dat_inode(nilfs), (void *)raw_sr +
+       nilfs_write_inode_common(nilfs->ns_dat, (void *)raw_sr +
                                 NILFS_SR_DAT_OFFSET(isz), 1);
        nilfs_write_inode_common(nilfs->ns_cpfile, (void *)raw_sr +
                                 NILFS_SR_CPFILE_OFFSET(isz), 1);
@@ -1179,7 +1159,7 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
                sci->sc_stage.scnt++;  /* Fall through */
        case NILFS_ST_DAT:
  dat_stage:
-               err = nilfs_segctor_scan_file(sci, nilfs_dat_inode(nilfs),
+               err = nilfs_segctor_scan_file(sci, nilfs->ns_dat,
                                              &nilfs_sc_dat_ops);
                if (unlikely(err))
                        break;
@@ -1563,7 +1543,6 @@ nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci,
        return 0;
 
  failed_bmap:
-       err = nilfs_handle_bmap_error(err, __func__, inode, sci->sc_super);
        return err;
 }
 
@@ -1783,6 +1762,7 @@ static void nilfs_clear_copied_buffers(struct list_head *list, int err)
                                if (!err) {
                                        set_buffer_uptodate(bh);
                                        clear_buffer_dirty(bh);
+                                       clear_buffer_delay(bh);
                                        clear_buffer_nilfs_volatile(bh);
                                }
                                brelse(bh); /* for b_assoc_buffers */
@@ -1909,6 +1889,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
                                    b_assoc_buffers) {
                        set_buffer_uptodate(bh);
                        clear_buffer_dirty(bh);
+                       clear_buffer_delay(bh);
                        clear_buffer_nilfs_volatile(bh);
                        clear_buffer_nilfs_redirected(bh);
                        if (bh == segbuf->sb_super_root) {
index e2dcc9c733f7f755ea43edd8f8dc7d4aa736d2a8..70dfdd532b83d9158c16f17df6741869f4a7f8bf 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/crc32.h>
 #include <linux/vfs.h>
 #include <linux/writeback.h>
-#include <linux/kobject.h>
 #include <linux/seq_file.h>
 #include <linux/mount.h>
 #include "nilfs.h"
@@ -111,12 +110,17 @@ void nilfs_error(struct super_block *sb, const char *function,
                 const char *fmt, ...)
 {
        struct nilfs_sb_info *sbi = NILFS_SB(sb);
+       struct va_format vaf;
        va_list args;
 
        va_start(args, fmt);
-       printk(KERN_CRIT "NILFS error (device %s): %s: ", sb->s_id, function);
-       vprintk(fmt, args);
-       printk("\n");
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       printk(KERN_CRIT "NILFS error (device %s): %s: %pV\n",
+              sb->s_id, function, &vaf);
+
        va_end(args);
 
        if (!(sb->s_flags & MS_RDONLY)) {
@@ -136,13 +140,17 @@ void nilfs_error(struct super_block *sb, const char *function,
 void nilfs_warning(struct super_block *sb, const char *function,
                   const char *fmt, ...)
 {
+       struct va_format vaf;
        va_list args;
 
        va_start(args, fmt);
-       printk(KERN_WARNING "NILFS warning (device %s): %s: ",
-              sb->s_id, function);
-       vprintk(fmt, args);
-       printk("\n");
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       printk(KERN_WARNING "NILFS warning (device %s): %s: %pV\n",
+              sb->s_id, function, &vaf);
+
        va_end(args);
 }
 
@@ -1010,11 +1018,11 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
        struct nilfs_sb_info *sbi = NILFS_SB(sb);
        struct the_nilfs *nilfs = sbi->s_nilfs;
        unsigned long old_sb_flags;
-       struct nilfs_mount_options old_opts;
+       unsigned long old_mount_opt;
        int err;
 
        old_sb_flags = sb->s_flags;
-       old_opts.mount_opt = sbi->s_mount_opt;
+       old_mount_opt = sbi->s_mount_opt;
 
        if (!parse_options(data, sb, 1)) {
                err = -EINVAL;
@@ -1083,7 +1091,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
 
  restore_opts:
        sb->s_flags = old_sb_flags;
-       sbi->s_mount_opt = old_opts.mount_opt;
+       sbi->s_mount_opt = old_mount_opt;
        return err;
 }
 
index 0254be2d73c6f5cb70c2468208dce7997df3386a..ad4ac607cf5734fda535667e898ad9b4cccaab63 100644 (file)
@@ -329,7 +329,6 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
        printk(KERN_INFO "NILFS: recovery complete.\n");
 
  skip_recovery:
-       set_nilfs_loaded(nilfs);
        nilfs_clear_recovery_info(&ri);
        sbi->s_super->s_flags = s_flags;
        return 0;
@@ -651,12 +650,11 @@ int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump,
 
 int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks)
 {
-       struct inode *dat = nilfs_dat_inode(nilfs);
        unsigned long ncleansegs;
 
-       down_read(&NILFS_MDT(dat)->mi_sem);     /* XXX */
+       down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
        ncleansegs = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile);
-       up_read(&NILFS_MDT(dat)->mi_sem);       /* XXX */
+       up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
        *nblocks = (sector_t)ncleansegs * nilfs->ns_blocks_per_segment;
        return 0;
 }
index 69226e14b7450384a0db42c5d8d7fc5eb5156fb4..fd85e4c05c6b2b850da079b2282280754f72eaf6 100644 (file)
@@ -36,8 +36,6 @@
 /* the_nilfs struct */
 enum {
        THE_NILFS_INIT = 0,     /* Information from super_block is set */
-       THE_NILFS_LOADED,       /* Roll-back/roll-forward has done and
-                                  the latest checkpoint was loaded */
        THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */
        THE_NILFS_GC_RUNNING,   /* gc process is running */
        THE_NILFS_SB_DIRTY,     /* super block is dirty */
@@ -178,7 +176,6 @@ static inline int nilfs_##name(struct the_nilfs *nilfs)                     \
 }
 
 THE_NILFS_FNS(INIT, init)
-THE_NILFS_FNS(LOADED, loaded)
 THE_NILFS_FNS(DISCONTINUED, discontinued)
 THE_NILFS_FNS(GC_RUNNING, gc_running)
 THE_NILFS_FNS(SB_DIRTY, sb_dirty)
index 9f26ac9be2a45d38e340bed6d51164492fab0ca6..9e3d45bcb5fd14b9c744bfef26a1358c766f9b03 100644 (file)
@@ -307,8 +307,7 @@ static void o2hb_arm_write_timeout(struct o2hb_region *reg)
 
 static void o2hb_disarm_write_timeout(struct o2hb_region *reg)
 {
-       cancel_delayed_work(&reg->hr_write_timeout_work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&reg->hr_write_timeout_work);
 }
 
 static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc)
index cf3e16696216d4fa95f30c0247ee58e608f54047..a87366750f23ae1f97719661e067acaa1b077604 100644 (file)
@@ -325,5 +325,7 @@ void o2quo_init(void)
 
 void o2quo_exit(void)
 {
-       flush_scheduled_work();
+       struct o2quo_state *qs = &o2quo_state;
+
+       flush_work_sync(&qs->qs_work);
 }
index 30ac27345586ea7b943a0042f0f2d52df7acc2f8..0a12eb89cd32b544aa720804d2836c4c6d2c8a3c 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/sysfs.h>
 #include <linux/xattr.h>
 #include <linux/security.h>
 #include "sysfs.h"
index ffaaa816bfba4c3c1c845e772845749675210e30..3d28af31d86300ecbddde7b4dc9d7eb25a255dc6 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/lockdep.h>
+#include <linux/kobject_ns.h>
 #include <linux/fs.h>
 
 struct sysfs_open_dirent;
index 45ce15dc5b2b05a7447e6ad2a9834dd0bf5b6dec..edfa178bafb62e4d147dc74ba9593b622231c25d 100644 (file)
@@ -408,7 +408,7 @@ xfs_mru_cache_flush(
        spin_lock(&mru->lock);
        if (mru->queued) {
                spin_unlock(&mru->lock);
-               cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work);
+               cancel_delayed_work_sync(&mru->work);
                spin_lock(&mru->lock);
        }
 
index 5ae1d07d4a1275a8ac91996b23753270e5033cb3..6bf9355fa7eb5097c59454ac8d98e46e09c1f621 100644 (file)
@@ -22,15 +22,15 @@ DECLARE_PER_CPU(struct pt_regs *, __irq_regs);
 
 static inline struct pt_regs *get_irq_regs(void)
 {
-       return __get_cpu_var(__irq_regs);
+       return __this_cpu_read(__irq_regs);
 }
 
 static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
 {
-       struct pt_regs *old_regs, **pp_regs = &__get_cpu_var(__irq_regs);
+       struct pt_regs *old_regs;
 
-       old_regs = *pp_regs;
-       *pp_regs = new_regs;
+       old_regs = __this_cpu_read(__irq_regs);
+       __this_cpu_write(__irq_regs, new_regs);
        return old_regs;
 }
 
index bd69d79208de644e9b5ef2c2a3723ee3ab6aa5fc..05cbad03c5abeba469c5f025cba8991fbe397719 100644 (file)
@@ -67,7 +67,8 @@
  * Align to a 32 byte boundary equal to the
  * alignment gcc 4.5 uses for a struct
  */
-#define STRUCT_ALIGN() . = ALIGN(32)
+#define STRUCT_ALIGNMENT 32
+#define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT)
 
 /* The actual configuration determine if the init/exit sections
  * are handled as text/data or they can be discarded (which
 #define TRACE_SYSCALLS()
 #endif
 
+
+#define KERNEL_DTB()                                                   \
+       STRUCT_ALIGN();                                                 \
+       VMLINUX_SYMBOL(__dtb_start) = .;                                \
+       *(.dtb.init.rodata)                                             \
+       VMLINUX_SYMBOL(__dtb_end) = .;
+
 /* .data section */
 #define DATA_DATA                                                      \
        *(.data)                                                        \
        MCOUNT_REC()                                                    \
        DEV_DISCARD(init.rodata)                                        \
        CPU_DISCARD(init.rodata)                                        \
-       MEM_DISCARD(init.rodata)
+       MEM_DISCARD(init.rodata)                                        \
+       KERNEL_DTB()
 
 #define INIT_TEXT                                                      \
        *(.init.text)                                                   \
diff --git a/include/keys/encrypted-type.h b/include/keys/encrypted-type.h
new file mode 100644 (file)
index 0000000..9585501
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef _KEYS_ENCRYPTED_TYPE_H
+#define _KEYS_ENCRYPTED_TYPE_H
+
+#include <linux/key.h>
+#include <linux/rcupdate.h>
+
+struct encrypted_key_payload {
+       struct rcu_head rcu;
+       char *master_desc;      /* datablob: master key name */
+       char *datalen;          /* datablob: decrypted key length */
+       u8 *iv;                 /* datablob: iv */
+       u8 *encrypted_data;     /* datablob: encrypted data */
+       unsigned short datablob_len;    /* length of datablob */
+       unsigned short decrypted_datalen;       /* decrypted data length */
+       u8 decrypted_data[0];   /* decrypted data +  datablob + hmac */
+};
+
+extern struct key_type key_type_encrypted;
+
+#endif /* _KEYS_ENCRYPTED_TYPE_H */
diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
new file mode 100644 (file)
index 0000000..56f82e5
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 IBM Corporation
+ * Author: David Safford <safford@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef _KEYS_TRUSTED_TYPE_H
+#define _KEYS_TRUSTED_TYPE_H
+
+#include <linux/key.h>
+#include <linux/rcupdate.h>
+
+#define MIN_KEY_SIZE                   32
+#define MAX_KEY_SIZE                   128
+#define MAX_BLOB_SIZE                  320
+
+struct trusted_key_payload {
+       struct rcu_head rcu;
+       unsigned int key_len;
+       unsigned int blob_len;
+       unsigned char migratable;
+       unsigned char key[MAX_KEY_SIZE + 1];
+       unsigned char blob[MAX_BLOB_SIZE];
+};
+
+extern struct key_type key_type_trusted;
+
+#endif /* _KEYS_TRUSTED_TYPE_H */
index a354c199ab98a3bfa32d5ef98a1e5b1684675baf..d1580c17cab3323b22db1b2455b17a07bb34fed4 100644 (file)
@@ -20,15 +20,18 @@ header-y += wimax/
 objhdr-y += version.h
 
 ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/a.out.h \
-                 $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
+                 $(srctree)/include/asm-$(SRCARCH)/a.out.h \
+                 $(INSTALL_HDR_PATH)/include/asm-*/a.out.h),)
 header-y += a.out.h
 endif
 ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/kvm.h \
-                 $(srctree)/include/asm-$(SRCARCH)/kvm.h),)
+                 $(srctree)/include/asm-$(SRCARCH)/kvm.h \
+                 $(INSTALL_HDR_PATH)/include/asm-*/kvm.h),)
 header-y += kvm.h
 endif
 ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/kvm_para.h \
-                 $(srctree)/include/asm-$(SRCARCH)/kvm_para.h),)
+                 $(srctree)/include/asm-$(SRCARCH)/kvm_para.h \
+                 $(INSTALL_HDR_PATH)/include/asm-*/kvm_para.h),)
 header-y += kvm_para.h
 endif
 
index 8b5c0620abf95ba50223ced24c2e558eaaf73d54..359df048769059bfe24883d00149f8f3a4727872 100644 (file)
@@ -372,6 +372,7 @@ struct audit_buffer;
 struct audit_context;
 struct inode;
 struct netlink_skb_parms;
+struct path;
 struct linux_binprm;
 struct mq_attr;
 struct mqstat;
index 90012b9ddbf3e5f999983bf7d2f6e388a99d25a1..fb16a3699b99f682c88bea8cdbb71c0862ca368f 100644 (file)
@@ -246,7 +246,6 @@ struct cpu_vfs_cap_data {
 /* Allow configuration of the secure attention key */
 /* Allow administration of the random device */
 /* Allow examination and configuration of disk quotas */
-/* Allow configuring the kernel's syslog (printk behaviour) */
 /* Allow setting the domainname */
 /* Allow setting the hostname */
 /* Allow calling bdflush() */
@@ -352,7 +351,11 @@ struct cpu_vfs_cap_data {
 
 #define CAP_MAC_ADMIN        33
 
-#define CAP_LAST_CAP         CAP_MAC_ADMIN
+/* Allow configuring the kernel's syslog (printk behaviour) */
+
+#define CAP_SYSLOG           34
+
+#define CAP_LAST_CAP         CAP_SYSLOG
 
 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
 
index bd07758943e0da21aab61afd8b70c13a723d72d9..59fcd24b146861a205803e3c1a7b4c7c3e478135 100644 (file)
@@ -307,7 +307,7 @@ extern struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
  * __d_rcu_to_refcount - take a refcount on dentry if sequence check is ok
  * @dentry: dentry to take a ref on
  * @seq: seqcount to verify against
- * @Returns: 0 on failure, else 1.
+ * Returns: 0 on failure, else 1.
  *
  * __d_rcu_to_refcount operates on a dentry,seq pair that was returned
  * by __d_lookup_rcu, to get a reference on an rcu-walk dentry.
index 24c806f12a6c96966b0764a9224821fcc5bee434..5ac3bdd5cee677ab7ff752c8ea87a959b35e134a 100644 (file)
 #ifdef CONFIG_PROFILING
  
 #include <linux/dcache.h>
-#include <linux/path.h>
 #include <linux/types.h>
  
 struct dcookie_user;
+struct path;
  
 /**
  * dcookie_register - register a user of dcookies
index dd489531346864be7031cd9d7937e29b44db3e00..d96af9701d60b7104066ef4cbf1487aeff10daf5 100644 (file)
@@ -197,6 +197,7 @@ struct class {
 
        struct class_attribute          *class_attrs;
        struct device_attribute         *dev_attrs;
+       struct bin_attribute            *dev_bin_attrs;
        struct kobject                  *dev_kobj;
 
        int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
@@ -508,13 +509,13 @@ static inline int device_is_registered(struct device *dev)
 
 static inline void device_enable_async_suspend(struct device *dev)
 {
-       if (dev->power.status == DPM_ON)
+       if (!dev->power.in_suspend)
                dev->power.async_suspend = true;
 }
 
 static inline void device_disable_async_suspend(struct device *dev)
 {
-       if (dev->power.status == DPM_ON)
+       if (!dev->power.in_suspend)
                dev->power.async_suspend = false;
 }
 
index 4fd978e7eb83ef8d689d0d313b5441b0631ea275..4d857973d2c94317cf11041a4a7070794fc13a99 100644 (file)
@@ -195,15 +195,9 @@ enum {
 /*
  * io context count accounting
  */
-#define elv_ioc_count_mod(name, __val)                         \
-       do {                                                    \
-               preempt_disable();                              \
-               __get_cpu_var(name) += (__val);                 \
-               preempt_enable();                               \
-       } while (0)
-
-#define elv_ioc_count_inc(name)        elv_ioc_count_mod(name, 1)
-#define elv_ioc_count_dec(name)        elv_ioc_count_mod(name, -1)
+#define elv_ioc_count_mod(name, __val) this_cpu_add(name, __val)
+#define elv_ioc_count_inc(name)        this_cpu_inc(name)
+#define elv_ioc_count_dec(name)        this_cpu_dec(name)
 
 #define elv_ioc_count_read(name)                               \
 ({                                                             \
index 1cd637ef62d2ff73be203a76e930e73c87b209f1..9a3f5f9383f69748ff4cb5857694de9c6fe9e296 100644 (file)
@@ -302,9 +302,9 @@ struct fw_packet {
 struct fw_transaction {
        int node_id; /* The generation is implied; it is always the current. */
        int tlabel;
-       int timestamp;
        struct list_head link;
        struct fw_card *card;
+       bool is_split_transaction;
        struct timer_list split_timeout_timer;
 
        struct fw_packet packet;
index c6dcc1dfe78111bb1f32c127809ae956db789d10..43fe52fcef0f60973cb61c33a30e0cbb00450811 100644 (file)
@@ -17,7 +17,6 @@
 #define _LINUX_FIRMWARE_MAP_H
 
 #include <linux/list.h>
-#include <linux/kobject.h>
 
 /*
  * provide a dummy interface if CONFIG_FIRMWARE_MEMMAP is disabled
index 631b77f2ac70fb38c1481305bd4f088c1073e7d7..70e4efabe0fb6983ed9524f4ade4e5d91e2ce2d0 100644 (file)
@@ -71,7 +71,7 @@ void *flex_array_get(struct flex_array *fa, unsigned int element_nr);
 int flex_array_shrink(struct flex_array *fa);
 
 #define flex_array_put_ptr(fa, nr, src, gfp) \
-       flex_array_put(fa, nr, &(void *)(src), gfp)
+       flex_array_put(fa, nr, (void *)&(src), gfp)
 
 void *flex_array_get_ptr(struct flex_array *fa, unsigned int element_nr);
 
index baf3e556ff0ed3f2e9d993a53e1f3850dd0fc8d1..f84d9928bdb16c75ea5cb0575892f8d7437c02bb 100644 (file)
@@ -382,7 +382,6 @@ struct inodes_stat_t {
 #include <linux/path.h>
 #include <linux/stat.h>
 #include <linux/cache.h>
-#include <linux/kobject.h>
 #include <linux/list.h>
 #include <linux/radix-tree.h>
 #include <linux/prio_tree.h>
@@ -402,6 +401,7 @@ struct hd_geometry;
 struct iovec;
 struct nameidata;
 struct kiocb;
+struct kobject;
 struct pipe_inode_info;
 struct poll_table_struct;
 struct kstatfs;
index c3c578e098332100bbac52ff5d9884e0ec810def..d464de53db4399c598ec3793f75290856b049255 100644 (file)
  * 7.15
  *  - add store notify
  *  - add retrieve notify
+ *
+ * 7.16
+ *  - add BATCH_FORGET request
+ *  - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct
+ *    fuse_ioctl_iovec' instead of ambiguous 'struct iovec'
+ *  - add FUSE_IOCTL_32BIT flag
  */
 
 #ifndef _LINUX_FUSE_H
@@ -72,7 +78,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 15
+#define FUSE_KERNEL_MINOR_VERSION 16
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -200,12 +206,14 @@ struct fuse_file_lock {
  * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
  * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
  * FUSE_IOCTL_RETRY: retry with new iovecs
+ * FUSE_IOCTL_32BIT: 32bit ioctl
  *
  * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
  */
 #define FUSE_IOCTL_COMPAT      (1 << 0)
 #define FUSE_IOCTL_UNRESTRICTED        (1 << 1)
 #define FUSE_IOCTL_RETRY       (1 << 2)
+#define FUSE_IOCTL_32BIT       (1 << 3)
 
 #define FUSE_IOCTL_MAX_IOV     256
 
@@ -256,6 +264,7 @@ enum fuse_opcode {
        FUSE_IOCTL         = 39,
        FUSE_POLL          = 40,
        FUSE_NOTIFY_REPLY  = 41,
+       FUSE_BATCH_FORGET  = 42,
 
        /* CUSE specific operations */
        CUSE_INIT          = 4096,
@@ -290,6 +299,16 @@ struct fuse_forget_in {
        __u64   nlookup;
 };
 
+struct fuse_forget_one {
+       __u64   nodeid;
+       __u64   nlookup;
+};
+
+struct fuse_batch_forget_in {
+       __u32   count;
+       __u32   dummy;
+};
+
 struct fuse_getattr_in {
        __u32   getattr_flags;
        __u32   dummy;
@@ -510,6 +529,11 @@ struct fuse_ioctl_in {
        __u32   out_size;
 };
 
+struct fuse_ioctl_iovec {
+       __u64   base;
+       __u64   len;
+};
+
 struct fuse_ioctl_out {
        __s32   result;
        __u32   flags;
index bb0f56f5c01ef81c51808e7cd97fe9543567ae1e..20b9801f669bf53750043b5402ecce92a680c25a 100644 (file)
@@ -820,6 +820,49 @@ static inline void hid_hw_stop(struct hid_device *hdev)
        hdev->ll_driver->stop(hdev);
 }
 
+/**
+ * hid_hw_open - signal underlaying HW to start delivering events
+ *
+ * @hdev: hid device
+ *
+ * Tell underlying HW to start delivering events from the device.
+ * This function should be called sometime after successful call
+ * to hid_hiw_start().
+ */
+static inline int __must_check hid_hw_open(struct hid_device *hdev)
+{
+       return hdev->ll_driver->open(hdev);
+}
+
+/**
+ * hid_hw_close - signal underlaying HW to stop delivering events
+ *
+ * @hdev: hid device
+ *
+ * This function indicates that we are not interested in the events
+ * from this device anymore. Delivery of events may or may not stop,
+ * depending on the number of users still outstanding.
+ */
+static inline void hid_hw_close(struct hid_device *hdev)
+{
+       hdev->ll_driver->close(hdev);
+}
+
+/**
+ * hid_hw_power - requests underlying HW to go into given power mode
+ *
+ * @hdev: hid device
+ * @level: requested power level (one of %PM_HINT_* defines)
+ *
+ * This function requests underlying hardware to enter requested power
+ * mode.
+ */
+
+static inline int hid_hw_power(struct hid_device *hdev, int level)
+{
+       return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0;
+}
+
 void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
                int interrupt);
 
@@ -838,12 +881,32 @@ int hid_pidff_init(struct hid_device *hid);
 #define hid_pidff_init NULL
 #endif
 
-#define dbg_hid(format, arg...) if (hid_debug) \
-                               printk(KERN_DEBUG "%s: " format ,\
-                               __FILE__ , ## arg)
-#define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
-               __FILE__ , ## arg)
-#endif /* HID_FF */
+#define dbg_hid(format, arg...)                                                \
+do {                                                                   \
+       if (hid_debug)                                                  \
+               printk(KERN_DEBUG "%s: " format, __FILE__, ##arg);      \
+} while (0)
+
+#define hid_printk(level, hid, fmt, arg...)            \
+       dev_printk(level, &(hid)->dev, fmt, ##arg)
+#define hid_emerg(hid, fmt, arg...)                    \
+       dev_emerg(&(hid)->dev, fmt, ##arg)
+#define hid_crit(hid, fmt, arg...)                     \
+       dev_crit(&(hid)->dev, fmt, ##arg)
+#define hid_alert(hid, fmt, arg...)                    \
+       dev_alert(&(hid)->dev, fmt, ##arg)
+#define hid_err(hid, fmt, arg...)                      \
+       dev_err(&(hid)->dev, fmt, ##arg)
+#define hid_notice(hid, fmt, arg...)                   \
+       dev_notice(&(hid)->dev, fmt, ##arg)
+#define hid_warn(hid, fmt, arg...)                     \
+       dev_warn(&(hid)->dev, fmt, ##arg)
+#define hid_info(hid, fmt, arg...)                     \
+       dev_info(&(hid)->dev, fmt, ##arg)
+#define hid_dbg(hid, fmt, arg...)                      \
+       dev_dbg(&(hid)->dev, fmt, ##arg)
+
+#endif /* __KERNEL__ */
 
 #endif
 
index b676c585574e1723a50fbb7bddf0b96d43706dbe..3a93f73a8acc8001bb69d6fcf2f0cd871030aeaa 100644 (file)
@@ -81,7 +81,8 @@ DECLARE_PER_CPU(int, __kmap_atomic_idx);
 
 static inline int kmap_atomic_idx_push(void)
 {
-       int idx = __get_cpu_var(__kmap_atomic_idx)++;
+       int idx = __this_cpu_inc_return(__kmap_atomic_idx) - 1;
+
 #ifdef CONFIG_DEBUG_HIGHMEM
        WARN_ON_ONCE(in_irq() && !irqs_disabled());
        BUG_ON(idx > KM_TYPE_NR);
@@ -91,16 +92,18 @@ static inline int kmap_atomic_idx_push(void)
 
 static inline int kmap_atomic_idx(void)
 {
-       return __get_cpu_var(__kmap_atomic_idx) - 1;
+       return __this_cpu_read(__kmap_atomic_idx) - 1;
 }
 
-static inline int kmap_atomic_idx_pop(void)
+static inline void kmap_atomic_idx_pop(void)
 {
-       int idx = --__get_cpu_var(__kmap_atomic_idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
+       int idx = __this_cpu_dec_return(__kmap_atomic_idx);
+
        BUG_ON(idx < 0);
+#else
+       __this_cpu_dec(__kmap_atomic_idx);
 #endif
-       return idx;
 }
 
 #endif
index 330586ffffbbccad534b1f81b7309d766f8d48fb..f376ddc64c4dd164a6d1304e017242ffe0f356a8 100644 (file)
@@ -131,7 +131,6 @@ struct hrtimer_sleeper {
  * @index:             clock type index for per_cpu support when moving a
  *                     timer to a base on another cpu.
  * @active:            red black tree root node for the active timers
- * @first:             pointer to the timer node which expires first
  * @resolution:                the resolution of the clock, in nanoseconds
  * @get_time:          function to retrieve the current time of the clock
  * @softirq_time:      the time when running the hrtimer queue in the softirq
diff --git a/include/linux/i2c/ds620.h b/include/linux/i2c/ds620.h
new file mode 100644 (file)
index 0000000..736bb87
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _LINUX_DS620_H
+#define _LINUX_DS620_H
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+/* platform data for the DS620 temperature sensor and thermostat */
+
+struct ds620_platform_data {
+       /*
+        *  Thermostat output pin PO mode:
+        *  0 = always low (default)
+        *  1 = PO_LOW
+        *  2 = PO_HIGH
+        *
+        * (see Documentation/hwmon/ds620)
+        */
+       int pomode;
+};
+
+#endif /* _LINUX_DS620_H */
index b6de9a6f7018b6132de91c7142bafefdd1e68962..d0fbc043de604ea0e2dd1b2911087a9d19215c96 100644 (file)
@@ -56,6 +56,8 @@
 
 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+/* The `const' in roundup() prevents gcc-3.3 from calling __divdi3 */
 #define roundup(x, y) (                                        \
 {                                                      \
        const typeof(y) __y = y;                        \
@@ -263,6 +265,7 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
 }
 
 extern int hex_to_bin(char ch);
+extern void hex2bin(u8 *dst, const char *src, size_t count);
 
 /*
  * General tracing related utility functions - trace_printk(),
index ad54c846911b91a169b903f7b1f6fee24d4320a2..44e83ba12b5b1076e4a1af7624420a9c2762ed2f 100644 (file)
@@ -47,7 +47,7 @@ extern unsigned long long nr_context_switches(void);
 
 #ifndef CONFIG_GENERIC_HARDIRQS
 #define kstat_irqs_this_cpu(irq) \
-       (kstat_this_cpu.irqs[irq])
+       (this_cpu_read(kstat.irqs[irq])
 
 struct irq_desc;
 
index b78edb58ee66164e756b4789baf71ab86e8684c4..dd7c12e875bcc987abea835fc96b18cd3416a0eb 100644 (file)
@@ -305,12 +305,12 @@ struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk);
 /* kprobe_running() will just return the current_kprobe on this CPU */
 static inline struct kprobe *kprobe_running(void)
 {
-       return (__get_cpu_var(current_kprobe));
+       return (__this_cpu_read(current_kprobe));
 }
 
 static inline void reset_current_kprobe(void)
 {
-       __get_cpu_var(current_kprobe) = NULL;
+       __this_cpu_write(current_kprobe, NULL);
 }
 
 static inline struct kprobe_ctlblk *get_kprobe_ctlblk(void)
index d947b1231662b9f69b388d0c5e3393972285faa3..c9c5d7ad1a2bc0aefffe9cb8942aa32c5b6c3c4f 100644 (file)
@@ -996,8 +996,7 @@ extern int ata_sas_port_init(struct ata_port *);
 extern int ata_sas_port_start(struct ata_port *ap);
 extern void ata_sas_port_stop(struct ata_port *ap);
 extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *);
-extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
-                           struct ata_port *ap);
+extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap);
 extern int sata_scr_valid(struct ata_link *link);
 extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
 extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
@@ -1040,8 +1039,7 @@ extern unsigned int ata_do_dev_read_id(struct ata_device *dev,
                                        struct ata_taskfile *tf, u16 *id);
 extern void ata_qc_complete(struct ata_queued_cmd *qc);
 extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active);
-extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
-                             void (*done)(struct scsi_cmnd *));
+extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd);
 extern int ata_std_bios_param(struct scsi_device *sdev,
                              struct block_device *bdev,
                              sector_t capacity, int geom[]);
index 8aea06f0564ca9843b05812d2d21b23712b9c30c..2feda6ee6140a52dcd589f0ac597ffe8d17db339 100644 (file)
@@ -3,7 +3,7 @@
 #include <linux/ioport.h>
 #include <linux/of.h>
 
-extern u64 of_translate_address(struct device_node *np, const u32 *addr);
+extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
 extern int of_address_to_resource(struct device_node *dev, int index,
                                  struct resource *r);
 extern void __iomem *of_iomap(struct device_node *device, int index);
@@ -21,7 +21,7 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
 #endif
 
 #ifdef CONFIG_PCI
-extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no,
+extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no,
                               u64 *size, unsigned int *flags);
 extern int of_pci_address_to_resource(struct device_node *dev, int bar,
                                      struct resource *r);
@@ -32,7 +32,7 @@ static inline int of_pci_address_to_resource(struct device_node *dev, int bar,
        return -ENOSYS;
 }
 
-static inline const u32 *of_get_pci_address(struct device_node *dev,
+static inline const __be32 *of_get_pci_address(struct device_node *dev,
                int bar_no, u64 *size, unsigned int *flags)
 {
        return NULL;
index 7bbf5b32843897a4b09c700a430221a6f6002897..0ef22a1f129e9f8b5d8cf95b451c70ce4cbd8d3f 100644 (file)
@@ -58,6 +58,23 @@ struct boot_param_header {
 };
 
 #if defined(CONFIG_OF_FLATTREE)
+
+struct device_node;
+
+/* For scanning an arbitrary device-tree at any time */
+extern char *of_fdt_get_string(struct boot_param_header *blob, u32 offset);
+extern void *of_fdt_get_property(struct boot_param_header *blob,
+                                unsigned long node,
+                                const char *name,
+                                unsigned long *size);
+extern int of_fdt_is_compatible(struct boot_param_header *blob,
+                               unsigned long node,
+                               const char *compat);
+extern int of_fdt_match(struct boot_param_header *blob, unsigned long node,
+                       const char **compat);
+extern void of_fdt_unflatten_tree(unsigned long *blob,
+                              struct device_node **mynodes);
+
 /* TBD: Temporary export of fdt globals - remove when code fully merged */
 extern int __initdata dt_root_addr_cells;
 extern int __initdata dt_root_size_cells;
@@ -71,6 +88,7 @@ extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname,
 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 int of_flat_dt_match(unsigned long node, const char **matches);
 extern unsigned long of_get_flat_dt_root(void);
 
 extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
diff --git a/include/linux/of_net.h b/include/linux/of_net.h
new file mode 100644 (file)
index 0000000..e913081
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * OF helpers for network devices.
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_OF_NET_H
+#define __LINUX_OF_NET_H
+
+#ifdef CONFIG_OF_NET
+#include <linux/of.h>
+extern const void *of_get_mac_address(struct device_node *np);
+#endif
+
+#endif /* __LINUX_OF_NET_H */
index 5095b834a6fb52f1f746257805f34cdabf186528..27c3c6fcfad321a4915cba6b3ab6162cb10c19a1 100644 (file)
@@ -240,6 +240,21 @@ extern void __bad_size_call_parameter(void);
        pscr_ret__;                                                     \
 })
 
+#define __pcpu_size_call_return2(stem, variable, ...)                  \
+({                                                                     \
+       typeof(variable) pscr2_ret__;                                   \
+       __verify_pcpu_ptr(&(variable));                                 \
+       switch(sizeof(variable)) {                                      \
+       case 1: pscr2_ret__ = stem##1(variable, __VA_ARGS__); break;    \
+       case 2: pscr2_ret__ = stem##2(variable, __VA_ARGS__); break;    \
+       case 4: pscr2_ret__ = stem##4(variable, __VA_ARGS__); break;    \
+       case 8: pscr2_ret__ = stem##8(variable, __VA_ARGS__); break;    \
+       default:                                                        \
+               __bad_size_call_parameter(); break;                     \
+       }                                                               \
+       pscr2_ret__;                                                    \
+})
+
 #define __pcpu_size_call(stem, variable, ...)                          \
 do {                                                                   \
        __verify_pcpu_ptr(&(variable));                                 \
@@ -402,6 +417,89 @@ do {                                                                       \
 # define this_cpu_xor(pcp, val)                __pcpu_size_call(this_cpu_or_, (pcp), (val))
 #endif
 
+#define _this_cpu_generic_add_return(pcp, val)                         \
+({                                                                     \
+       typeof(pcp) ret__;                                              \
+       preempt_disable();                                              \
+       __this_cpu_add(pcp, val);                                       \
+       ret__ = __this_cpu_read(pcp);                                   \
+       preempt_enable();                                               \
+       ret__;                                                          \
+})
+
+#ifndef this_cpu_add_return
+# ifndef this_cpu_add_return_1
+#  define this_cpu_add_return_1(pcp, val)      _this_cpu_generic_add_return(pcp, val)
+# endif
+# ifndef this_cpu_add_return_2
+#  define this_cpu_add_return_2(pcp, val)      _this_cpu_generic_add_return(pcp, val)
+# endif
+# ifndef this_cpu_add_return_4
+#  define this_cpu_add_return_4(pcp, val)      _this_cpu_generic_add_return(pcp, val)
+# endif
+# ifndef this_cpu_add_return_8
+#  define this_cpu_add_return_8(pcp, val)      _this_cpu_generic_add_return(pcp, val)
+# endif
+# define this_cpu_add_return(pcp, val) __pcpu_size_call_return2(this_cpu_add_return_, pcp, val)
+#endif
+
+#define this_cpu_sub_return(pcp, val)  this_cpu_add_return(pcp, -(val))
+#define this_cpu_inc_return(pcp)       this_cpu_add_return(pcp, 1)
+#define this_cpu_dec_return(pcp)       this_cpu_add_return(pcp, -1)
+
+#define _this_cpu_generic_xchg(pcp, nval)                              \
+({     typeof(pcp) ret__;                                              \
+       preempt_disable();                                              \
+       ret__ = __this_cpu_read(pcp);                                   \
+       __this_cpu_write(pcp, nval);                                    \
+       preempt_enable();                                               \
+       ret__;                                                          \
+})
+
+#ifndef this_cpu_xchg
+# ifndef this_cpu_xchg_1
+#  define this_cpu_xchg_1(pcp, nval)   _this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef this_cpu_xchg_2
+#  define this_cpu_xchg_2(pcp, nval)   _this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef this_cpu_xchg_4
+#  define this_cpu_xchg_4(pcp, nval)   _this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef this_cpu_xchg_8
+#  define this_cpu_xchg_8(pcp, nval)   _this_cpu_generic_xchg(pcp, nval)
+# endif
+# define this_cpu_xchg(pcp, nval)      \
+       __pcpu_size_call_return2(this_cpu_xchg_, (pcp), nval)
+#endif
+
+#define _this_cpu_generic_cmpxchg(pcp, oval, nval)                     \
+({     typeof(pcp) ret__;                                              \
+       preempt_disable();                                              \
+       ret__ = __this_cpu_read(pcp);                                   \
+       if (ret__ == (oval))                                            \
+               __this_cpu_write(pcp, nval);                            \
+       preempt_enable();                                               \
+       ret__;                                                          \
+})
+
+#ifndef this_cpu_cmpxchg
+# ifndef this_cpu_cmpxchg_1
+#  define this_cpu_cmpxchg_1(pcp, oval, nval)  _this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef this_cpu_cmpxchg_2
+#  define this_cpu_cmpxchg_2(pcp, oval, nval)  _this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef this_cpu_cmpxchg_4
+#  define this_cpu_cmpxchg_4(pcp, oval, nval)  _this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef this_cpu_cmpxchg_8
+#  define this_cpu_cmpxchg_8(pcp, oval, nval)  _this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# define this_cpu_cmpxchg(pcp, oval, nval)     \
+       __pcpu_size_call_return2(this_cpu_cmpxchg_, pcp, oval, nval)
+#endif
+
 /*
  * Generic percpu operations that do not require preemption handling.
  * Either we do not care about races or the caller has the
@@ -529,11 +627,87 @@ do {                                                                      \
 # define __this_cpu_xor(pcp, val)      __pcpu_size_call(__this_cpu_xor_, (pcp), (val))
 #endif
 
+#define __this_cpu_generic_add_return(pcp, val)                                \
+({                                                                     \
+       __this_cpu_add(pcp, val);                                       \
+       __this_cpu_read(pcp);                                           \
+})
+
+#ifndef __this_cpu_add_return
+# ifndef __this_cpu_add_return_1
+#  define __this_cpu_add_return_1(pcp, val)    __this_cpu_generic_add_return(pcp, val)
+# endif
+# ifndef __this_cpu_add_return_2
+#  define __this_cpu_add_return_2(pcp, val)    __this_cpu_generic_add_return(pcp, val)
+# endif
+# ifndef __this_cpu_add_return_4
+#  define __this_cpu_add_return_4(pcp, val)    __this_cpu_generic_add_return(pcp, val)
+# endif
+# ifndef __this_cpu_add_return_8
+#  define __this_cpu_add_return_8(pcp, val)    __this_cpu_generic_add_return(pcp, val)
+# endif
+# define __this_cpu_add_return(pcp, val)       __pcpu_size_call_return2(this_cpu_add_return_, pcp, val)
+#endif
+
+#define __this_cpu_sub_return(pcp, val)        this_cpu_add_return(pcp, -(val))
+#define __this_cpu_inc_return(pcp)     this_cpu_add_return(pcp, 1)
+#define __this_cpu_dec_return(pcp)     this_cpu_add_return(pcp, -1)
+
+#define __this_cpu_generic_xchg(pcp, nval)                             \
+({     typeof(pcp) ret__;                                              \
+       ret__ = __this_cpu_read(pcp);                                   \
+       __this_cpu_write(pcp, nval);                                    \
+       ret__;                                                          \
+})
+
+#ifndef __this_cpu_xchg
+# ifndef __this_cpu_xchg_1
+#  define __this_cpu_xchg_1(pcp, nval) __this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef __this_cpu_xchg_2
+#  define __this_cpu_xchg_2(pcp, nval) __this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef __this_cpu_xchg_4
+#  define __this_cpu_xchg_4(pcp, nval) __this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef __this_cpu_xchg_8
+#  define __this_cpu_xchg_8(pcp, nval) __this_cpu_generic_xchg(pcp, nval)
+# endif
+# define __this_cpu_xchg(pcp, nval)    \
+       __pcpu_size_call_return2(__this_cpu_xchg_, (pcp), nval)
+#endif
+
+#define __this_cpu_generic_cmpxchg(pcp, oval, nval)                    \
+({                                                                     \
+       typeof(pcp) ret__;                                              \
+       ret__ = __this_cpu_read(pcp);                                   \
+       if (ret__ == (oval))                                            \
+               __this_cpu_write(pcp, nval);                            \
+       ret__;                                                          \
+})
+
+#ifndef __this_cpu_cmpxchg
+# ifndef __this_cpu_cmpxchg_1
+#  define __this_cpu_cmpxchg_1(pcp, oval, nval)        __this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef __this_cpu_cmpxchg_2
+#  define __this_cpu_cmpxchg_2(pcp, oval, nval)        __this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef __this_cpu_cmpxchg_4
+#  define __this_cpu_cmpxchg_4(pcp, oval, nval)        __this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef __this_cpu_cmpxchg_8
+#  define __this_cpu_cmpxchg_8(pcp, oval, nval)        __this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# define __this_cpu_cmpxchg(pcp, oval, nval)   \
+       __pcpu_size_call_return2(__this_cpu_cmpxchg_, pcp, oval, nval)
+#endif
+
 /*
  * IRQ safe versions of the per cpu RMW operations. Note that these operations
  * are *not* safe against modification of the same variable from another
  * processors (which one gets when using regular atomic operations)
. They are guaranteed to be atomic vs. local interrupts and
* They are guaranteed to be atomic vs. local interrupts and
  * preemption only.
  */
 #define irqsafe_cpu_generic_to_op(pcp, val, op)                                \
@@ -620,4 +794,33 @@ do {                                                                       \
 # define irqsafe_cpu_xor(pcp, val) __pcpu_size_call(irqsafe_cpu_xor_, (val))
 #endif
 
+#define irqsafe_cpu_generic_cmpxchg(pcp, oval, nval)                   \
+({                                                                     \
+       typeof(pcp) ret__;                                              \
+       unsigned long flags;                                            \
+       local_irq_save(flags);                                          \
+       ret__ = __this_cpu_read(pcp);                                   \
+       if (ret__ == (oval))                                            \
+               __this_cpu_write(pcp, nval);                            \
+       local_irq_restore(flags);                                       \
+       ret__;                                                          \
+})
+
+#ifndef irqsafe_cpu_cmpxchg
+# ifndef irqsafe_cpu_cmpxchg_1
+#  define irqsafe_cpu_cmpxchg_1(pcp, oval, nval)       irqsafe_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef irqsafe_cpu_cmpxchg_2
+#  define irqsafe_cpu_cmpxchg_2(pcp, oval, nval)       irqsafe_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef irqsafe_cpu_cmpxchg_4
+#  define irqsafe_cpu_cmpxchg_4(pcp, oval, nval)       irqsafe_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef irqsafe_cpu_cmpxchg_8
+#  define irqsafe_cpu_cmpxchg_8(pcp, oval, nval)       irqsafe_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# define irqsafe_cpu_cmpxchg(pcp, oval, nval)          \
+       __pcpu_size_call_return2(irqsafe_cpu_cmpxchg_, (pcp), oval, nval)
+#endif
+
 #endif /* __LINUX_PERCPU_H */
index bb27d7ec2fb95cac4599351532f482d1df129fab..77257c92155aa4efb6ea68d9c99298426aedc60b 100644 (file)
@@ -30,6 +30,7 @@ struct pipe_buffer {
  *     struct pipe_inode_info - a linux kernel pipe
  *     @wait: reader/writer wait point in case of empty/full pipe
  *     @nrbufs: the number of non-empty pipe buffers in this pipe
+ *     @buffers: total number of buffers (should be a power of 2)
  *     @curbuf: the current pipe buffer entry
  *     @tmp_page: cached released page
  *     @readers: number of current readers of this pipe
index 40f3f45702bac82a8e454812b67a4419b7d36362..dd9c7ab38270059a147090ff87d37b45e591bc75 100644 (file)
@@ -366,45 +366,6 @@ extern struct dev_pm_ops generic_subsys_pm_ops;
 #define PMSG_AUTO_RESUME       ((struct pm_message) \
                                        { .event = PM_EVENT_AUTO_RESUME, })
 
-/**
- * Device power management states
- *
- * These state labels are used internally by the PM core to indicate the current
- * status of a device with respect to the PM core operations.
- *
- * DPM_ON              Device is regarded as operational.  Set this way
- *                     initially and when ->complete() is about to be called.
- *                     Also set when ->prepare() fails.
- *
- * DPM_PREPARING       Device is going to be prepared for a PM transition.  Set
- *                     when ->prepare() is about to be called.
- *
- * DPM_RESUMING                Device is going to be resumed.  Set when ->resume(),
- *                     ->thaw(), or ->restore() is about to be called.
- *
- * DPM_SUSPENDING      Device has been prepared for a power transition.  Set
- *                     when ->prepare() has just succeeded.
- *
- * DPM_OFF             Device is regarded as inactive.  Set immediately after
- *                     ->suspend(), ->freeze(), or ->poweroff() has succeeded.
- *                     Also set when ->resume()_noirq, ->thaw_noirq(), or
- *                     ->restore_noirq() is about to be called.
- *
- * DPM_OFF_IRQ         Device is in a "deep sleep".  Set immediately after
- *                     ->suspend_noirq(), ->freeze_noirq(), or
- *                     ->poweroff_noirq() has just succeeded.
- */
-
-enum dpm_state {
-       DPM_INVALID,
-       DPM_ON,
-       DPM_PREPARING,
-       DPM_RESUMING,
-       DPM_SUSPENDING,
-       DPM_OFF,
-       DPM_OFF_IRQ,
-};
-
 /**
  * Device run-time power management status.
  *
@@ -463,8 +424,8 @@ struct wakeup_source;
 struct dev_pm_info {
        pm_message_t            power_state;
        unsigned int            can_wakeup:1;
-       unsigned                async_suspend:1;
-       enum dpm_state          status;         /* Owned by the PM core */
+       unsigned int            async_suspend:1;
+       unsigned int            in_suspend:1;   /* Owned by the PM core */
        spinlock_t              lock;
 #ifdef CONFIG_PM_SLEEP
        struct list_head        entry;
@@ -486,6 +447,7 @@ struct dev_pm_info {
        unsigned int            run_wake:1;
        unsigned int            runtime_auto:1;
        unsigned int            no_callbacks:1;
+       unsigned int            irq_safe:1;
        unsigned int            use_autosuspend:1;
        unsigned int            timer_autosuspends:1;
        enum rpm_request        request;
@@ -610,4 +572,11 @@ extern unsigned int        pm_flags;
 #define PM_APM 1
 #define PM_ACPI        2
 
+extern int pm_generic_suspend(struct device *dev);
+extern int pm_generic_resume(struct device *dev);
+extern int pm_generic_freeze(struct device *dev);
+extern int pm_generic_thaw(struct device *dev);
+extern int pm_generic_restore(struct device *dev);
+extern int pm_generic_poweroff(struct device *dev);
+
 #endif /* _LINUX_PM_H */
index d19f1cca7f740a9150f516c98e5c9deecfd271ae..d34f067e2a7f31e5b391b22382b811913b407515 100644 (file)
@@ -40,6 +40,7 @@ extern int pm_generic_runtime_idle(struct device *dev);
 extern int pm_generic_runtime_suspend(struct device *dev);
 extern int pm_generic_runtime_resume(struct device *dev);
 extern void pm_runtime_no_callbacks(struct device *dev);
+extern void pm_runtime_irq_safe(struct device *dev);
 extern void __pm_runtime_use_autosuspend(struct device *dev, bool use);
 extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
 extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
@@ -81,6 +82,11 @@ static inline bool pm_runtime_suspended(struct device *dev)
                && !dev->power.disable_depth;
 }
 
+static inline bool pm_runtime_enabled(struct device *dev)
+{
+       return !dev->power.disable_depth;
+}
+
 static inline void pm_runtime_mark_last_busy(struct device *dev)
 {
        ACCESS_ONCE(dev->power.last_busy) = jiffies;
@@ -119,11 +125,13 @@ static inline void pm_runtime_put_noidle(struct device *dev) {}
 static inline bool device_run_wake(struct device *dev) { return false; }
 static inline void device_set_run_wake(struct device *dev, bool enable) {}
 static inline bool pm_runtime_suspended(struct device *dev) { return false; }
+static inline bool pm_runtime_enabled(struct device *dev) { return false; }
 
 static inline int pm_generic_runtime_idle(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
 static inline void pm_runtime_no_callbacks(struct device *dev) {}
+static inline void pm_runtime_irq_safe(struct device *dev) {}
 
 static inline void pm_runtime_mark_last_busy(struct device *dev) {}
 static inline void __pm_runtime_use_autosuspend(struct device *dev,
@@ -196,6 +204,11 @@ static inline int pm_runtime_put_sync(struct device *dev)
        return __pm_runtime_idle(dev, RPM_GET_PUT);
 }
 
+static inline int pm_runtime_put_sync_suspend(struct device *dev)
+{
+       return __pm_runtime_suspend(dev, RPM_GET_PUT);
+}
+
 static inline int pm_runtime_put_sync_autosuspend(struct device *dev)
 {
        return __pm_runtime_suspend(dev, RPM_GET_PUT | RPM_AUTO);
similarity index 90%
rename from arch/arm/plat-pxa/include/plat/ssp.h
rename to include/linux/pxa2xx_ssp.h
index fe43150690ed4afa177eb1a2bc5c24f83089fbbd..2f691e4e6222202a9968a0d10fc9f56347c2244d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  ssp.h
+ *  pxa2xx_ssp.h
  *
  *  Copyright (C) 2003 Russell King, All Rights Reserved.
  *
@@ -16,8 +16,8 @@
  *       PXA3xx     SSP1, SSP2, SSP3, SSP4
  */
 
-#ifndef __ASM_ARCH_SSP_H
-#define __ASM_ARCH_SSP_H
+#ifndef __LINUX_SSP_H
+#define __LINUX_SSP_H
 
 #include <linux/list.h>
 #include <linux/io.h>
 #define SSCR1_SPO      (1 << 3)        /* Motorola SPI SSPSCLK polarity setting */
 #define SSCR1_SPH      (1 << 4)        /* Motorola SPI SSPSCLK phase setting */
 #define SSCR1_MWDS     (1 << 5)        /* Microwire Transmit Data Size */
-#define SSCR1_TFT      (0x000003c0)    /* Transmit FIFO Threshold (mask) */
-#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
-#define SSCR1_RFT      (0x00003c00)    /* Receive FIFO Threshold (mask) */
-#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
 
+#define SSSR_ALT_FRM_MASK      3       /* Masks the SFRM signal number */
 #define SSSR_TNF       (1 << 2)        /* Transmit FIFO Not Full */
 #define SSSR_RNE       (1 << 3)        /* Receive FIFO Not Empty */
 #define SSSR_BSY       (1 << 4)        /* SSP Busy */
 #define SSSR_RFS       (1 << 6)        /* Receive FIFO Service Request */
 #define SSSR_ROR       (1 << 7)        /* Receive FIFO Overrun */
 
+#ifdef CONFIG_ARCH_PXA
+#define RX_THRESH_DFLT 8
+#define TX_THRESH_DFLT 8
+
+#define SSSR_TFL_MASK  (0xf << 8)      /* Transmit FIFO Level mask */
+#define SSSR_RFL_MASK  (0xf << 12)     /* Receive FIFO Level mask */
+
+#define SSCR1_TFT      (0x000003c0)    /* Transmit FIFO Threshold (mask) */
+#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
+#define SSCR1_RFT      (0x00003c00)    /* Receive FIFO Threshold (mask) */
+#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
+
+#else
+
+#define RX_THRESH_DFLT 2
+#define TX_THRESH_DFLT 2
+
+#define SSSR_TFL_MASK  (0x3 << 8)      /* Transmit FIFO Level mask */
+#define SSSR_RFL_MASK  (0x3 << 12)     /* Receive FIFO Level mask */
+
+#define SSCR1_TFT      (0x000000c0)    /* Transmit FIFO Threshold (mask) */
+#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..4] */
+#define SSCR1_RFT      (0x00000c00)    /* Receive FIFO Threshold (mask) */
+#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */
+#endif
 
 /* extra bits in PXA255, PXA26x and PXA27x SSP ports */
 #define SSCR0_TISSP            (1 << 4)        /* TI Sync Serial Protocol */
@@ -139,6 +161,7 @@ enum pxa_ssp_type {
        PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
        PXA27x_SSP,
        PXA168_SSP,
+       CE4100_SSP,
 };
 
 struct ssp_device {
@@ -183,4 +206,4 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
 
 struct ssp_device *pxa_ssp_request(int port, const char *label);
 void pxa_ssp_free(struct ssp_device *);
-#endif /* __ASM_ARCH_SSP_H */
+#endif
index 341acbbc434a3b7b4450d7fa109d1482ae711341..abc527aa8550200bfb229743d700fee8b0b168d3 100644 (file)
@@ -70,7 +70,6 @@ struct sched_param {
 #include <linux/smp.h>
 #include <linux/sem.h>
 #include <linux/signal.h>
-#include <linux/path.h>
 #include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/pid.h>
@@ -88,7 +87,6 @@ struct sched_param {
 #include <linux/timer.h>
 #include <linux/hrtimer.h>
 #include <linux/task_io_accounting.h>
-#include <linux/kobject.h>
 #include <linux/latencytop.h>
 #include <linux/cred.h>
 
index 1ac42475ea08a31d654c45ba60b1c49b6ca5bf0c..c642bb8b8f5a4894b3878a0977a017b684efefe4 100644 (file)
@@ -1058,8 +1058,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @cred points to the credentials to provide the context against which to
  *     evaluate the security data on the key.
  *     @perm describes the combination of permissions required of this key.
- *     Return 1 if permission granted, 0 if permission denied and -ve it the
- *     normal permissions model should be effected.
+ *     Return 0 if permission is granted, -ve error otherwise.
  * @key_getsecurity:
  *     Get a textual representation of the security context attached to a key
  *     for the purposes of honouring KEYCTL_GETSECURITY.  This function
index 791a502f69063a2255c3e41d6c47e865e0c1f610..83203ae9390b0227f1c58fbf8629797f55f4c39c 100644 (file)
@@ -138,11 +138,12 @@ void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
 void *__kmalloc(size_t size, gfp_t flags);
 
 #ifdef CONFIG_TRACING
-extern void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags);
+extern void *kmem_cache_alloc_trace(size_t size,
+                                   struct kmem_cache *cachep, gfp_t flags);
 extern size_t slab_buffer_size(struct kmem_cache *cachep);
 #else
 static __always_inline void *
-kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags)
+kmem_cache_alloc_trace(size_t size, struct kmem_cache *cachep, gfp_t flags)
 {
        return kmem_cache_alloc(cachep, flags);
 }
@@ -179,10 +180,7 @@ found:
 #endif
                        cachep = malloc_sizes[i].cs_cachep;
 
-               ret = kmem_cache_alloc_notrace(cachep, flags);
-
-               trace_kmalloc(_THIS_IP_, ret,
-                             size, slab_buffer_size(cachep), flags);
+               ret = kmem_cache_alloc_trace(size, cachep, flags);
 
                return ret;
        }
@@ -194,14 +192,16 @@ extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
 extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
 
 #ifdef CONFIG_TRACING
-extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep,
-                                          gfp_t flags,
-                                          int nodeid);
+extern void *kmem_cache_alloc_node_trace(size_t size,
+                                        struct kmem_cache *cachep,
+                                        gfp_t flags,
+                                        int nodeid);
 #else
 static __always_inline void *
-kmem_cache_alloc_node_notrace(struct kmem_cache *cachep,
-                             gfp_t flags,
-                             int nodeid)
+kmem_cache_alloc_node_trace(size_t size,
+                           struct kmem_cache *cachep,
+                           gfp_t flags,
+                           int nodeid)
 {
        return kmem_cache_alloc_node(cachep, flags, nodeid);
 }
@@ -210,7 +210,6 @@ kmem_cache_alloc_node_notrace(struct kmem_cache *cachep,
 static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
 {
        struct kmem_cache *cachep;
-       void *ret;
 
        if (__builtin_constant_p(size)) {
                int i = 0;
@@ -234,13 +233,7 @@ found:
 #endif
                        cachep = malloc_sizes[i].cs_cachep;
 
-               ret = kmem_cache_alloc_node_notrace(cachep, flags, node);
-
-               trace_kmalloc_node(_THIS_IP_, ret,
-                                  size, slab_buffer_size(cachep),
-                                  flags, node);
-
-               return ret;
+               return kmem_cache_alloc_node_trace(size, cachep, flags, node);
        }
        return __kmalloc_node(size, flags, node);
 }
index e4f5ed180b9bbe226714f2b40fd0d95516ad3c12..8b6e8ae5d5cabcd6f267405a1007d56de0070b64 100644 (file)
@@ -10,9 +10,8 @@
 #include <linux/gfp.h>
 #include <linux/workqueue.h>
 #include <linux/kobject.h>
-#include <linux/kmemleak.h>
 
-#include <trace/events/kmem.h>
+#include <linux/kmemleak.h>
 
 enum stat_item {
        ALLOC_FASTPATH,         /* Allocation from cpu slab */
@@ -216,31 +215,40 @@ static __always_inline struct kmem_cache *kmalloc_slab(size_t size)
 void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
 void *__kmalloc(size_t size, gfp_t flags);
 
+static __always_inline void *
+kmalloc_order(size_t size, gfp_t flags, unsigned int order)
+{
+       void *ret = (void *) __get_free_pages(flags | __GFP_COMP, order);
+       kmemleak_alloc(ret, size, 1, flags);
+       return ret;
+}
+
 #ifdef CONFIG_TRACING
-extern void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags);
+extern void *
+kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size);
+extern void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order);
 #else
 static __always_inline void *
-kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags)
+kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
 {
        return kmem_cache_alloc(s, gfpflags);
 }
+
+static __always_inline void *
+kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
+{
+       return kmalloc_order(size, flags, order);
+}
 #endif
 
 static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
 {
        unsigned int order = get_order(size);
-       void *ret = (void *) __get_free_pages(flags | __GFP_COMP, order);
-
-       kmemleak_alloc(ret, size, 1, flags);
-       trace_kmalloc(_THIS_IP_, ret, size, PAGE_SIZE << order, flags);
-
-       return ret;
+       return kmalloc_order_trace(size, flags, order);
 }
 
 static __always_inline void *kmalloc(size_t size, gfp_t flags)
 {
-       void *ret;
-
        if (__builtin_constant_p(size)) {
                if (size > SLUB_MAX_SIZE)
                        return kmalloc_large(size, flags);
@@ -251,11 +259,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
                        if (!s)
                                return ZERO_SIZE_PTR;
 
-                       ret = kmem_cache_alloc_notrace(s, flags);
-
-                       trace_kmalloc(_THIS_IP_, ret, size, s->size, flags);
-
-                       return ret;
+                       return kmem_cache_alloc_trace(s, flags, size);
                }
        }
        return __kmalloc(size, flags);
@@ -266,14 +270,14 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node);
 void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
 
 #ifdef CONFIG_TRACING
-extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *s,
+extern void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
                                           gfp_t gfpflags,
-                                          int node);
+                                          int node, size_t size);
 #else
 static __always_inline void *
-kmem_cache_alloc_node_notrace(struct kmem_cache *s,
+kmem_cache_alloc_node_trace(struct kmem_cache *s,
                              gfp_t gfpflags,
-                             int node)
+                             int node, size_t size)
 {
        return kmem_cache_alloc_node(s, gfpflags, node);
 }
@@ -281,8 +285,6 @@ kmem_cache_alloc_node_notrace(struct kmem_cache *s,
 
 static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
 {
-       void *ret;
-
        if (__builtin_constant_p(size) &&
                size <= SLUB_MAX_SIZE && !(flags & SLUB_DMA)) {
                        struct kmem_cache *s = kmalloc_slab(size);
@@ -290,12 +292,7 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
                if (!s)
                        return ZERO_SIZE_PTR;
 
-               ret = kmem_cache_alloc_node_notrace(s, flags, node);
-
-               trace_kmalloc_node(_THIS_IP_, ret,
-                                  size, s->size, flags, node);
-
-               return ret;
+               return kmem_cache_alloc_node_trace(s, flags, node, size);
        }
        return __kmalloc_node(size, flags, node);
 }
index c91302f3a25789b8045b34d9c0a9fa814c29b0ae..6cd10f6ad4727c75e3c193c420a908b8963abc7a 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef DW_SPI_HEADER_H
 #define DW_SPI_HEADER_H
+
 #include <linux/io.h>
 
 /* Bit fields in CTRLR0 */
@@ -82,6 +83,13 @@ struct dw_spi_reg {
                                though only low 16 bits matters */
 } __packed;
 
+struct dw_spi;
+struct dw_spi_dma_ops {
+       int (*dma_init)(struct dw_spi *dws);
+       void (*dma_exit)(struct dw_spi *dws);
+       int (*dma_transfer)(struct dw_spi *dws, int cs_change);
+};
+
 struct dw_spi {
        struct spi_master       *master;
        struct spi_device       *cur_dev;
@@ -136,13 +144,15 @@ struct dw_spi {
        /* Dma info */
        int                     dma_inited;
        struct dma_chan         *txchan;
+       struct scatterlist      tx_sgl;
        struct dma_chan         *rxchan;
-       int                     txdma_done;
-       int                     rxdma_done;
-       u64                     tx_param;
-       u64                     rx_param;
+       struct scatterlist      rx_sgl;
+       int                     dma_chan_done;
        struct device           *dma_dev;
-       dma_addr_t              dma_addr;
+       dma_addr_t              dma_addr; /* phy address of the Data register */
+       struct dw_spi_dma_ops   *dma_ops;
+       void                    *dma_priv; /* platform relate info */
+       struct pci_dev          *dmac;
 
        /* Bus interface info */
        void                    *priv;
@@ -216,4 +226,8 @@ extern int dw_spi_add_host(struct dw_spi *dws);
 extern void dw_spi_remove_host(struct dw_spi *dws);
 extern int dw_spi_suspend_host(struct dw_spi *dws);
 extern int dw_spi_resume_host(struct dw_spi *dws);
+extern void dw_spi_xfer_done(struct dw_spi *dws);
+
+/* platform related setup */
+extern int dw_spi_mid_init(struct dw_spi *dws); /* Intel MID platforms */
 #endif /* DW_SPI_HEADER_H */
diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h
new file mode 100644 (file)
index 0000000..d3e1075
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __linux_pxa2xx_spi_h
+#define __linux_pxa2xx_spi_h
+
+#include <linux/pxa2xx_ssp.h>
+
+#define PXA2XX_CS_ASSERT (0x01)
+#define PXA2XX_CS_DEASSERT (0x02)
+
+/* device.platform_data for SSP controller devices */
+struct pxa2xx_spi_master {
+       u32 clock_enable;
+       u16 num_chipselect;
+       u8 enable_dma;
+};
+
+/* spi_board_info.controller_data for SPI slave devices,
+ * copied to spi_device.platform_data ... mostly for dma tuning
+ */
+struct pxa2xx_spi_chip {
+       u8 tx_threshold;
+       u8 rx_threshold;
+       u8 dma_burst_size;
+       u32 timeout;
+       u8 enable_loopback;
+       int gpio_cs;
+       void (*cs_control)(u32 command);
+};
+
+#ifdef CONFIG_ARCH_PXA
+
+#include <linux/clk.h>
+#include <mach/dma.h>
+
+extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info);
+
+#else
+/*
+ * This is the implemtation for CE4100 on x86. ARM defines them in mach/ or
+ * plat/ include path.
+ * The CE4100 does not provide DMA support. This bits are here to let the driver
+ * compile and will never be used. Maybe we get DMA support at a later point in
+ * time.
+ */
+
+#define DCSR(n)         (n)
+#define DSADR(n)        (n)
+#define DTADR(n)        (n)
+#define DCMD(n)         (n)
+#define DRCMR(n)        (n)
+
+#define DCSR_RUN       (1 << 31)       /* Run Bit */
+#define DCSR_NODESC    (1 << 30)       /* No-Descriptor Fetch */
+#define DCSR_STOPIRQEN (1 << 29)       /* Stop Interrupt Enable */
+#define DCSR_REQPEND   (1 << 8)        /* Request Pending (read-only) */
+#define DCSR_STOPSTATE (1 << 3)        /* Stop State (read-only) */
+#define DCSR_ENDINTR   (1 << 2)        /* End Interrupt */
+#define DCSR_STARTINTR (1 << 1)        /* Start Interrupt */
+#define DCSR_BUSERR    (1 << 0)        /* Bus Error Interrupt */
+
+#define DCSR_EORIRQEN  (1 << 28)       /* End of Receive Interrupt Enable */
+#define DCSR_EORJMPEN  (1 << 27)       /* Jump to next descriptor on EOR */
+#define DCSR_EORSTOPEN (1 << 26)       /* STOP on an EOR */
+#define DCSR_SETCMPST  (1 << 25)       /* Set Descriptor Compare Status */
+#define DCSR_CLRCMPST  (1 << 24)       /* Clear Descriptor Compare Status */
+#define DCSR_CMPST     (1 << 10)       /* The Descriptor Compare Status */
+#define DCSR_EORINTR   (1 << 9)        /* The end of Receive */
+
+#define DRCMR_MAPVLD   (1 << 7)        /* Map Valid */
+#define DRCMR_CHLNUM   0x1f            /* mask for Channel Number */
+
+#define DDADR_DESCADDR 0xfffffff0      /* Address of next descriptor */
+#define DDADR_STOP     (1 << 0)        /* Stop */
+
+#define DCMD_INCSRCADDR        (1 << 31)       /* Source Address Increment Setting. */
+#define DCMD_INCTRGADDR        (1 << 30)       /* Target Address Increment Setting. */
+#define DCMD_FLOWSRC   (1 << 29)       /* Flow Control by the source. */
+#define DCMD_FLOWTRG   (1 << 28)       /* Flow Control by the target. */
+#define DCMD_STARTIRQEN        (1 << 22)       /* Start Interrupt Enable */
+#define DCMD_ENDIRQEN  (1 << 21)       /* End Interrupt Enable */
+#define DCMD_ENDIAN    (1 << 18)       /* Device Endian-ness. */
+#define DCMD_BURST8    (1 << 16)       /* 8 byte burst */
+#define DCMD_BURST16   (2 << 16)       /* 16 byte burst */
+#define DCMD_BURST32   (3 << 16)       /* 32 byte burst */
+#define DCMD_WIDTH1    (1 << 14)       /* 1 byte width */
+#define DCMD_WIDTH2    (2 << 14)       /* 2 byte width (HalfWord) */
+#define DCMD_WIDTH4    (3 << 14)       /* 4 byte width (Word) */
+#define DCMD_LENGTH    0x01fff         /* length mask (max = 8K - 1) */
+
+/*
+ * Descriptor structure for PXA's DMA engine
+ * Note: this structure must always be aligned to a 16-byte boundary.
+ */
+
+typedef enum {
+       DMA_PRIO_HIGH = 0,
+       DMA_PRIO_MEDIUM = 1,
+       DMA_PRIO_LOW = 2
+} pxa_dma_prio;
+
+/*
+ * DMA registration
+ */
+
+static inline int pxa_request_dma(char *name,
+               pxa_dma_prio prio,
+               void (*irq_handler)(int, void *),
+               void *data)
+{
+       return -ENODEV;
+}
+
+static inline void pxa_free_dma(int dma_ch)
+{
+}
+
+/*
+ * The CE4100 does not have the clk framework implemented and SPI clock can
+ * not be switched on/off or the divider changed.
+ */
+static inline void clk_disable(struct clk *clk)
+{
+}
+
+static inline int clk_enable(struct clk *clk)
+{
+       return 0;
+}
+
+static inline unsigned long clk_get_rate(struct clk *clk)
+{
+       return 3686400;
+}
+
+#endif
+#endif
index 6950c981882dfa4c30247e75fa93758145d0d2a9..78aa104250b7b78755b570480353d66c304062cf 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef _LINUX_SUNRPC_CACHE_H_
 #define _LINUX_SUNRPC_CACHE_H_
 
+#include <linux/kref.h>
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <linux/proc_fs.h>
index 26697514c5ece07d72f6e07022f43ee86d187de0..144b34be5c326a0a9ea88f3413c99760cc7b5dce 100644 (file)
@@ -292,7 +292,7 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
 /* drivers/base/power/wakeup.c */
 extern bool events_check_enabled;
 
-extern bool pm_check_wakeup_events(void);
+extern bool pm_wakeup_pending(void);
 extern bool pm_get_wakeup_count(unsigned int *count);
 extern bool pm_save_wakeup_count(unsigned int count);
 #else /* !CONFIG_PM_SLEEP */
@@ -309,7 +309,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
 
 #define pm_notifier(fn, pri)   do { (void)(fn); } while (0)
 
-static inline bool pm_check_wakeup_events(void) { return true; }
+static inline bool pm_wakeup_pending(void) { return false; }
 #endif /* !CONFIG_PM_SLEEP */
 
 extern struct mutex pm_mutex;
index ac5d1c1285d9ef674e6a4630747ad4b58b3aa171..fdc718abf83becac29f7dd3a01cabd8b6ad7f068 100644 (file)
@@ -31,6 +31,7 @@
 
 extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
 extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
+extern int tpm_send(u32 chip_num, void *cmd, size_t buflen);
 #else
 static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
        return -ENODEV;
@@ -38,5 +39,8 @@ static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
 static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) {
        return -ENODEV;
 }
+static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) {
+       return -ENODEV;
+}
 #endif
 #endif
diff --git a/include/linux/tpm_command.h b/include/linux/tpm_command.h
new file mode 100644 (file)
index 0000000..727512e
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __LINUX_TPM_COMMAND_H__
+#define __LINUX_TPM_COMMAND_H__
+
+/*
+ * TPM Command constants from specifications at
+ * http://www.trustedcomputinggroup.org
+ */
+
+/* Command TAGS */
+#define TPM_TAG_RQU_COMMAND             193
+#define TPM_TAG_RQU_AUTH1_COMMAND       194
+#define TPM_TAG_RQU_AUTH2_COMMAND       195
+#define TPM_TAG_RSP_COMMAND             196
+#define TPM_TAG_RSP_AUTH1_COMMAND       197
+#define TPM_TAG_RSP_AUTH2_COMMAND       198
+
+/* Command Ordinals */
+#define TPM_ORD_GETRANDOM               70
+#define TPM_ORD_OSAP                    11
+#define TPM_ORD_OIAP                    10
+#define TPM_ORD_SEAL                    23
+#define TPM_ORD_UNSEAL                  24
+
+/* Other constants */
+#define SRKHANDLE                       0x40000000
+#define TPM_NONCE_SIZE                  20
+
+#endif
index bd257fee60310184b52d0f8c15f1206f6a4f5dad..1ac11586a2f5a5e036a2adce96f830dd0d731e36 100644 (file)
@@ -409,7 +409,7 @@ static inline bool __cancel_delayed_work(struct delayed_work *work)
 }
 
 /* Obsolete. use cancel_delayed_work_sync() */
-static inline
+static inline __deprecated
 void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
                                        struct delayed_work *work)
 {
@@ -417,7 +417,7 @@ void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
 }
 
 /* Obsolete. use cancel_delayed_work_sync() */
-static inline
+static inline __deprecated
 void cancel_rearming_delayed_work(struct delayed_work *work)
 {
        cancel_delayed_work_sync(work);
index f1e5bde4b35acbab2a0a5a525d59dde6e017cc61..e6131ef98d8fb94de08edb0db70ad39055e47cec 100644 (file)
 #define XATTR_SMACK_SUFFIX "SMACK64"
 #define XATTR_SMACK_IPIN "SMACK64IPIN"
 #define XATTR_SMACK_IPOUT "SMACK64IPOUT"
+#define XATTR_SMACK_EXEC "SMACK64EXEC"
+#define XATTR_SMACK_TRANSMUTE "SMACK64TRANSMUTE"
 #define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
 #define XATTR_NAME_SMACKIPIN   XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
 #define XATTR_NAME_SMACKIPOUT  XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
+#define XATTR_NAME_SMACKEXEC   XATTR_SECURITY_PREFIX XATTR_SMACK_EXEC
+#define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE
 
 #define XATTR_CAPS_SUFFIX "capability"
 #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
index ea51770c01701e312f70f9a81357babbf93fb865..00799c1d46288fb491e6eb07ccf17dc8406883cc 100644 (file)
@@ -777,9 +777,6 @@ static void __init do_initcalls(void)
 
        for (fn = __early_initcall_end; fn < __initcall_end; fn++)
                do_one_initcall(*fn);
-
-       /* Make sure there is no pending stuff from the initcall sequence */
-       flush_scheduled_work();
 }
 
 /*
index 0b5ff083fa22fa381a6fc1f092a824f255bda01a..33e0a39cf359e41b159c74ddf28e6f747a1cbd5c 100644 (file)
@@ -121,7 +121,7 @@ $(obj)/configs.o: $(obj)/config_data.h
 # config_data.h contains the same information as ikconfig.h but gzipped.
 # Info from config_data can be extracted from /proc/config*
 targets += config_data.gz
-$(obj)/config_data.gz: .config FORCE
+$(obj)/config_data.gz: $(KCONFIG_CONFIG) FORCE
        $(call if_changed,gzip)
 
 quiet_cmd_ikconfiggz = IKCFG   $@
index 676149a4ac5ff497367a484e2b66c01e915ccefd..89c74861a3da94ea6b21720b40f59ce69a42b918 100644 (file)
@@ -69,7 +69,7 @@ static void __unhash_process(struct task_struct *p, bool group_dead)
 
                list_del_rcu(&p->tasks);
                list_del_init(&p->sibling);
-               __get_cpu_var(process_counts)--;
+               __this_cpu_dec(process_counts);
        }
        list_del_rcu(&p->thread_group);
 }
index dc1a8bbcea7b41e760ac0d97b767e399c6477db7..d9b44f20b6b079c096c524f4f659cc4c63f614c1 100644 (file)
@@ -1285,7 +1285,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                        attach_pid(p, PIDTYPE_SID, task_session(current));
                        list_add_tail(&p->sibling, &p->real_parent->children);
                        list_add_tail_rcu(&p->tasks, &init_task.tasks);
-                       __get_cpu_var(process_counts)++;
+                       __this_cpu_inc(process_counts);
                }
                attach_pid(p, PIDTYPE_PID, pid);
                nr_threads++;
index bd1d42b17cb2f52f5156506ba25d75376102af7f..66ecd2ead215a9cb88ca8ae9f674e1c82766a066 100644 (file)
@@ -104,8 +104,13 @@ bool freeze_task(struct task_struct *p, bool sig_only)
        }
 
        if (should_send_signal(p)) {
-               if (!signal_pending(p))
-                       fake_signal_wake_up(p);
+               fake_signal_wake_up(p);
+               /*
+                * fake_signal_wake_up() goes through p's scheduler
+                * lock and guarantees that TASK_STOPPED/TRACED ->
+                * TASK_RUNNING transition can't race with task state
+                * testing in try_to_freeze_tasks().
+                */
        } else if (sig_only) {
                return false;
        } else {
index f2429fc3438c4f1c2094e59fe54415dc30e4bb51..45da2b6920ab25a23e6cb885297ca76280e81e36 100644 (file)
@@ -497,7 +497,7 @@ static inline int hrtimer_is_hres_enabled(void)
  */
 static inline int hrtimer_hres_active(void)
 {
-       return __get_cpu_var(hrtimer_bases).hres_active;
+       return __this_cpu_read(hrtimer_bases.hres_active);
 }
 
 /*
index 90f881904bb1202ba1566f5db2e28eaf128551b9..c58fa7da8aef1683dac88d4d2608d1fdaa5cd4ab 100644 (file)
@@ -77,21 +77,21 @@ void __weak arch_irq_work_raise(void)
  */
 static void __irq_work_queue(struct irq_work *entry)
 {
-       struct irq_work **head, *next;
+       struct irq_work *next;
 
-       head = &get_cpu_var(irq_work_list);
+       preempt_disable();
 
        do {
-               next = *head;
+               next = __this_cpu_read(irq_work_list);
                /* Can assign non-atomic because we keep the flags set. */
                entry->next = next_flags(next, IRQ_WORK_FLAGS);
-       } while (cmpxchg(head, next, entry) != next);
+       } while (this_cpu_cmpxchg(irq_work_list, next, entry) != next);
 
        /* The list was empty, raise self-interrupt to start processing. */
        if (!irq_work_next(entry))
                arch_irq_work_raise();
 
-       put_cpu_var(irq_work_list);
+       preempt_enable();
 }
 
 /*
@@ -120,16 +120,16 @@ EXPORT_SYMBOL_GPL(irq_work_queue);
  */
 void irq_work_run(void)
 {
-       struct irq_work *list, **head;
+       struct irq_work *list;
 
-       head = &__get_cpu_var(irq_work_list);
-       if (*head == NULL)
+       if (this_cpu_read(irq_work_list) == NULL)
                return;
 
        BUG_ON(!in_irq());
        BUG_ON(!irqs_disabled());
 
-       list = xchg(head, NULL);
+       list = this_cpu_xchg(irq_work_list, NULL);
+
        while (list != NULL) {
                struct irq_work *entry = list;
 
index 7663e5df0e6f731f1804201a5e6cdf9b6162dd05..77981813a1e75d6c3c830dac5084bc37e47c1080 100644 (file)
@@ -317,12 +317,12 @@ void __kprobes free_optinsn_slot(kprobe_opcode_t * slot, int dirty)
 /* We have preemption disabled.. so it is safe to use __ versions */
 static inline void set_kprobe_instance(struct kprobe *kp)
 {
-       __get_cpu_var(kprobe_instance) = kp;
+       __this_cpu_write(kprobe_instance, kp);
 }
 
 static inline void reset_kprobe_instance(void)
 {
-       __get_cpu_var(kprobe_instance) = NULL;
+       __this_cpu_write(kprobe_instance, NULL);
 }
 
 /*
@@ -965,7 +965,7 @@ static void __kprobes aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
 static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
                                        int trapnr)
 {
-       struct kprobe *cur = __get_cpu_var(kprobe_instance);
+       struct kprobe *cur = __this_cpu_read(kprobe_instance);
 
        /*
         * if we faulted "during" the execution of a user specified
@@ -980,7 +980,7 @@ static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
 
 static int __kprobes aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       struct kprobe *cur = __get_cpu_var(kprobe_instance);
+       struct kprobe *cur = __this_cpu_read(kprobe_instance);
        int ret = 0;
 
        if (cur && cur->break_handler) {
index f9063c6b185d2917124f06350753ad96e0b184d1..b75597235d85fd3323c318f5c58bb8c04554f1fb 100644 (file)
@@ -1,7 +1,4 @@
-
-ifeq ($(CONFIG_PM_DEBUG),y)
-EXTRA_CFLAGS   +=      -DDEBUG
-endif
+ccflags-$(CONFIG_PM_DEBUG)     :=      -DDEBUG
 
 obj-$(CONFIG_PM)               += main.o
 obj-$(CONFIG_PM_SLEEP)         += console.o
index 048d0b5148319db70883ee0c9963459c22048385..870f72bc72aed308049e3862ee9f62a3cf9be4f4 100644 (file)
@@ -62,7 +62,7 @@ void hibernation_set_ops(struct platform_hibernation_ops *ops)
 {
        if (ops && !(ops->begin && ops->end &&  ops->pre_snapshot
            && ops->prepare && ops->finish && ops->enter && ops->pre_restore
-           && ops->restore_cleanup)) {
+           && ops->restore_cleanup && ops->leave)) {
                WARN_ON(1);
                return;
        }
@@ -278,7 +278,7 @@ static int create_image(int platform_mode)
                goto Enable_irqs;
        }
 
-       if (hibernation_test(TEST_CORE) || !pm_check_wakeup_events())
+       if (hibernation_test(TEST_CORE) || pm_wakeup_pending())
                goto Power_up;
 
        in_suspend = 1;
@@ -516,7 +516,7 @@ int hibernation_platform_enter(void)
 
        local_irq_disable();
        sysdev_suspend(PMSG_HIBERNATE);
-       if (!pm_check_wakeup_events()) {
+       if (pm_wakeup_pending()) {
                error = -EAGAIN;
                goto Power_up;
        }
@@ -647,6 +647,7 @@ int hibernate(void)
                swsusp_free();
                if (!error)
                        power_down();
+               in_suspend = 0;
                pm_restore_gfp_mask();
        } else {
                pr_debug("PM: Image restored successfully.\n");
index e50b4c1b2a0f7f8943acb041b5d8ab202c40d5cd..d6d2a10320e03ef0795108fd147d161616f1bab5 100644 (file)
@@ -64,6 +64,12 @@ static int try_to_freeze_tasks(bool sig_only)
                         * perturb a task in TASK_STOPPED or TASK_TRACED.
                         * It is "frozen enough".  If the task does wake
                         * up, it will immediately call try_to_freeze.
+                        *
+                        * Because freeze_task() goes through p's
+                        * scheduler lock after setting TIF_FREEZE, it's
+                        * guaranteed that either we see TASK_RUNNING or
+                        * try_to_stop() after schedule() in ptrace/signal
+                        * stop sees TIF_FREEZE.
                         */
                        if (!task_is_stopped_or_traced(p) &&
                            !freezer_should_skip(p))
@@ -79,7 +85,7 @@ static int try_to_freeze_tasks(bool sig_only)
                if (!todo || time_after(jiffies, end_time))
                        break;
 
-               if (!pm_check_wakeup_events()) {
+               if (pm_wakeup_pending()) {
                        wakeup = true;
                        break;
                }
index 031d5e3a61973464eec7e0e72791e423bfb3396f..8850df68794d89999272156ff06a2f8a0115fe4c 100644 (file)
@@ -164,7 +164,7 @@ static int suspend_enter(suspend_state_t state)
 
        error = sysdev_suspend(PMSG_SUSPEND);
        if (!error) {
-               if (!suspend_test(TEST_CORE) && pm_check_wakeup_events()) {
+               if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) {
                        error = suspend_ops->enter(state);
                        events_check_enabled = false;
                }
index 4642a5c439eb324b8d3e79872e589439c705cd20..f64b8997fc768f401831ac7d8d5ebac7945f5a6d 100644 (file)
@@ -273,12 +273,12 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
         * at open time.
         */
        if (type == SYSLOG_ACTION_OPEN || !from_file) {
-               if (dmesg_restrict && !capable(CAP_SYS_ADMIN))
-                       return -EPERM;
+               if (dmesg_restrict && !capable(CAP_SYSLOG))
+                       goto warn; /* switch to return -EPERM after 2.6.39 */
                if ((type != SYSLOG_ACTION_READ_ALL &&
                     type != SYSLOG_ACTION_SIZE_BUFFER) &&
-                   !capable(CAP_SYS_ADMIN))
-                       return -EPERM;
+                   !capable(CAP_SYSLOG))
+                       goto warn; /* switch to return -EPERM after 2.6.39 */
        }
 
        error = security_syslog(type);
@@ -422,6 +422,12 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
        }
 out:
        return error;
+warn:
+       /* remove after 2.6.39 */
+       if (capable(CAP_SYS_ADMIN))
+               WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN "
+                 "but no CAP_SYSLOG (deprecated and denied).\n");
+       return -EPERM;
 }
 
 SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
index d0ddfea6579d027809cfb0bce885289bac0f957e..dd4aea806f8ef63ba882af3a47d5981b366d4dc7 100644 (file)
@@ -364,8 +364,8 @@ void rcu_irq_exit(void)
        WARN_ON_ONCE(rdtp->dynticks & 0x1);
 
        /* If the interrupt queued a callback, get out of dyntick mode. */
-       if (__get_cpu_var(rcu_sched_data).nxtlist ||
-           __get_cpu_var(rcu_bh_data).nxtlist)
+       if (__this_cpu_read(rcu_sched_data.nxtlist) ||
+           __this_cpu_read(rcu_bh_data.nxtlist))
                set_need_resched();
 }
 
index c10150cb456bc0316d81e3acd5ccdebb772df394..0823778f87fc697482251ba39351d8e2ac3a9709 100644 (file)
@@ -70,7 +70,7 @@ char *softirq_to_name[NR_SOFTIRQS] = {
 static void wakeup_softirqd(void)
 {
        /* Interrupts are disabled: no need to stop preemption */
-       struct task_struct *tsk = __get_cpu_var(ksoftirqd);
+       struct task_struct *tsk = __this_cpu_read(ksoftirqd);
 
        if (tsk && tsk->state != TASK_RUNNING)
                wake_up_process(tsk);
@@ -388,8 +388,8 @@ void __tasklet_schedule(struct tasklet_struct *t)
 
        local_irq_save(flags);
        t->next = NULL;
-       *__get_cpu_var(tasklet_vec).tail = t;
-       __get_cpu_var(tasklet_vec).tail = &(t->next);
+       *__this_cpu_read(tasklet_vec.tail) = t;
+       __this_cpu_write(tasklet_vec.tail, &(t->next));
        raise_softirq_irqoff(TASKLET_SOFTIRQ);
        local_irq_restore(flags);
 }
@@ -402,8 +402,8 @@ void __tasklet_hi_schedule(struct tasklet_struct *t)
 
        local_irq_save(flags);
        t->next = NULL;
-       *__get_cpu_var(tasklet_hi_vec).tail = t;
-       __get_cpu_var(tasklet_hi_vec).tail = &(t->next);
+       *__this_cpu_read(tasklet_hi_vec.tail) = t;
+       __this_cpu_write(tasklet_hi_vec.tail,  &(t->next));
        raise_softirq_irqoff(HI_SOFTIRQ);
        local_irq_restore(flags);
 }
@@ -414,8 +414,8 @@ void __tasklet_hi_schedule_first(struct tasklet_struct *t)
 {
        BUG_ON(!irqs_disabled());
 
-       t->next = __get_cpu_var(tasklet_hi_vec).head;
-       __get_cpu_var(tasklet_hi_vec).head = t;
+       t->next = __this_cpu_read(tasklet_hi_vec.head);
+       __this_cpu_write(tasklet_hi_vec.head, t);
        __raise_softirq_irqoff(HI_SOFTIRQ);
 }
 
@@ -426,9 +426,9 @@ static void tasklet_action(struct softirq_action *a)
        struct tasklet_struct *list;
 
        local_irq_disable();
-       list = __get_cpu_var(tasklet_vec).head;
-       __get_cpu_var(tasklet_vec).head = NULL;
-       __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
+       list = __this_cpu_read(tasklet_vec.head);
+       __this_cpu_write(tasklet_vec.head, NULL);
+       __this_cpu_write(tasklet_vec.tail, &__get_cpu_var(tasklet_vec).head);
        local_irq_enable();
 
        while (list) {
@@ -449,8 +449,8 @@ static void tasklet_action(struct softirq_action *a)
 
                local_irq_disable();
                t->next = NULL;
-               *__get_cpu_var(tasklet_vec).tail = t;
-               __get_cpu_var(tasklet_vec).tail = &(t->next);
+               *__this_cpu_read(tasklet_vec.tail) = t;
+               __this_cpu_write(tasklet_vec.tail, &(t->next));
                __raise_softirq_irqoff(TASKLET_SOFTIRQ);
                local_irq_enable();
        }
@@ -461,9 +461,9 @@ static void tasklet_hi_action(struct softirq_action *a)
        struct tasklet_struct *list;
 
        local_irq_disable();
-       list = __get_cpu_var(tasklet_hi_vec).head;
-       __get_cpu_var(tasklet_hi_vec).head = NULL;
-       __get_cpu_var(tasklet_hi_vec).tail = &__get_cpu_var(tasklet_hi_vec).head;
+       list = __this_cpu_read(tasklet_hi_vec.head);
+       __this_cpu_write(tasklet_hi_vec.head, NULL);
+       __this_cpu_write(tasklet_hi_vec.tail, &__get_cpu_var(tasklet_hi_vec).head);
        local_irq_enable();
 
        while (list) {
@@ -484,8 +484,8 @@ static void tasklet_hi_action(struct softirq_action *a)
 
                local_irq_disable();
                t->next = NULL;
-               *__get_cpu_var(tasklet_hi_vec).tail = t;
-               __get_cpu_var(tasklet_hi_vec).tail = &(t->next);
+               *__this_cpu_read(tasklet_hi_vec.tail) = t;
+               __this_cpu_write(tasklet_hi_vec.tail, &(t->next));
                __raise_softirq_irqoff(HI_SOFTIRQ);
                local_irq_enable();
        }
@@ -802,16 +802,16 @@ static void takeover_tasklets(unsigned int cpu)
 
        /* Find end, append list for that CPU. */
        if (&per_cpu(tasklet_vec, cpu).head != per_cpu(tasklet_vec, cpu).tail) {
-               *(__get_cpu_var(tasklet_vec).tail) = per_cpu(tasklet_vec, cpu).head;
-               __get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).tail;
+               *__this_cpu_read(tasklet_vec.tail) = per_cpu(tasklet_vec, cpu).head;
+               this_cpu_write(tasklet_vec.tail, per_cpu(tasklet_vec, cpu).tail);
                per_cpu(tasklet_vec, cpu).head = NULL;
                per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
        }
        raise_softirq_irqoff(TASKLET_SOFTIRQ);
 
        if (&per_cpu(tasklet_hi_vec, cpu).head != per_cpu(tasklet_hi_vec, cpu).tail) {
-               *__get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).head;
-               __get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).tail;
+               *__this_cpu_read(tasklet_hi_vec.tail) = per_cpu(tasklet_hi_vec, cpu).head;
+               __this_cpu_write(tasklet_hi_vec.tail, per_cpu(tasklet_hi_vec, cpu).tail);
                per_cpu(tasklet_hi_vec, cpu).head = NULL;
                per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head;
        }
index 3308fd7f1b52f170e4da5dd7e26749aca652ef1b..69691eb4b715da804555e04c79aa4ba44ec2bdd3 100644 (file)
@@ -89,8 +89,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
                return -ENOMEM;
 
        if (!info) {
-               int seq = get_cpu_var(taskstats_seqnum)++;
-               put_cpu_var(taskstats_seqnum);
+               int seq = this_cpu_inc_return(taskstats_seqnum) - 1;
 
                reply = genlmsg_put(skb, 0, seq, &family, 0, cmd);
        } else
@@ -612,7 +611,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
                fill_tgid_exit(tsk);
        }
 
-       listeners = &__raw_get_cpu_var(listener_array);
+       listeners = __this_cpu_ptr(&listener_array);
        if (list_empty(&listeners->list))
                return;
 
index b6b898d2eeefc1b0627c613b3d23a9bd4b21876e..051bc80a0c435cf47a8dfb8a0f5d2d49d20e188c 100644 (file)
@@ -49,7 +49,7 @@ struct tick_device *tick_get_device(int cpu)
  */
 int tick_is_oneshot_available(void)
 {
-       struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
+       struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
 
        return dev && (dev->features & CLOCK_EVT_FEAT_ONESHOT);
 }
index aada0e52680ace6cc7d5e09a111a3879c1c6bda3..5cbc101f908b8483938c0153fc1ac023bcd1c784 100644 (file)
@@ -95,7 +95,7 @@ int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires,
  */
 int tick_program_event(ktime_t expires, int force)
 {
-       struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
+       struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
 
        return tick_dev_program_event(dev, expires, force);
 }
@@ -167,7 +167,7 @@ int tick_oneshot_mode_active(void)
        int ret;
 
        local_irq_save(flags);
-       ret = __get_cpu_var(tick_cpu_device).mode == TICKDEV_MODE_ONESHOT;
+       ret = __this_cpu_read(tick_cpu_device.mode) == TICKDEV_MODE_ONESHOT;
        local_irq_restore(flags);
 
        return ret;
index 6e7b575ac33cf2dcba3f9dc749f7039e6805a3f0..d7ebdf4cea98aa3829ba1ec6a57a67359d6a0c98 100644 (file)
@@ -118,12 +118,12 @@ static void __touch_watchdog(void)
 {
        int this_cpu = smp_processor_id();
 
-       __get_cpu_var(watchdog_touch_ts) = get_timestamp(this_cpu);
+       __this_cpu_write(watchdog_touch_ts, get_timestamp(this_cpu));
 }
 
 void touch_softlockup_watchdog(void)
 {
-       __raw_get_cpu_var(watchdog_touch_ts) = 0;
+       __this_cpu_write(watchdog_touch_ts, 0);
 }
 EXPORT_SYMBOL(touch_softlockup_watchdog);
 
@@ -167,12 +167,12 @@ void touch_softlockup_watchdog_sync(void)
 /* watchdog detector functions */
 static int is_hardlockup(void)
 {
-       unsigned long hrint = __get_cpu_var(hrtimer_interrupts);
+       unsigned long hrint = __this_cpu_read(hrtimer_interrupts);
 
-       if (__get_cpu_var(hrtimer_interrupts_saved) == hrint)
+       if (__this_cpu_read(hrtimer_interrupts_saved) == hrint)
                return 1;
 
-       __get_cpu_var(hrtimer_interrupts_saved) = hrint;
+       __this_cpu_write(hrtimer_interrupts_saved, hrint);
        return 0;
 }
 #endif
@@ -205,8 +205,8 @@ static void watchdog_overflow_callback(struct perf_event *event, int nmi,
        /* Ensure the watchdog never gets throttled */
        event->hw.interrupts = 0;
 
-       if (__get_cpu_var(watchdog_nmi_touch) == true) {
-               __get_cpu_var(watchdog_nmi_touch) = false;
+       if (__this_cpu_read(watchdog_nmi_touch) == true) {
+               __this_cpu_write(watchdog_nmi_touch, false);
                return;
        }
 
@@ -220,7 +220,7 @@ static void watchdog_overflow_callback(struct perf_event *event, int nmi,
                int this_cpu = smp_processor_id();
 
                /* only print hardlockups once */
-               if (__get_cpu_var(hard_watchdog_warn) == true)
+               if (__this_cpu_read(hard_watchdog_warn) == true)
                        return;
 
                if (hardlockup_panic)
@@ -228,16 +228,16 @@ static void watchdog_overflow_callback(struct perf_event *event, int nmi,
                else
                        WARN(1, "Watchdog detected hard LOCKUP on cpu %d", this_cpu);
 
-               __get_cpu_var(hard_watchdog_warn) = true;
+               __this_cpu_write(hard_watchdog_warn, true);
                return;
        }
 
-       __get_cpu_var(hard_watchdog_warn) = false;
+       __this_cpu_write(hard_watchdog_warn, false);
        return;
 }
 static void watchdog_interrupt_count(void)
 {
-       __get_cpu_var(hrtimer_interrupts)++;
+       __this_cpu_inc(hrtimer_interrupts);
 }
 #else
 static inline void watchdog_interrupt_count(void) { return; }
@@ -246,7 +246,7 @@ static inline void watchdog_interrupt_count(void) { return; }
 /* watchdog kicker functions */
 static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
 {
-       unsigned long touch_ts = __get_cpu_var(watchdog_touch_ts);
+       unsigned long touch_ts = __this_cpu_read(watchdog_touch_ts);
        struct pt_regs *regs = get_irq_regs();
        int duration;
 
@@ -254,18 +254,18 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
        watchdog_interrupt_count();
 
        /* kick the softlockup detector */
-       wake_up_process(__get_cpu_var(softlockup_watchdog));
+       wake_up_process(__this_cpu_read(softlockup_watchdog));
 
        /* .. and repeat */
        hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period()));
 
        if (touch_ts == 0) {
-               if (unlikely(__get_cpu_var(softlockup_touch_sync))) {
+               if (unlikely(__this_cpu_read(softlockup_touch_sync))) {
                        /*
                         * If the time stamp was touched atomically
                         * make sure the scheduler tick is up to date.
                         */
-                       __get_cpu_var(softlockup_touch_sync) = false;
+                       __this_cpu_write(softlockup_touch_sync, false);
                        sched_clock_tick();
                }
                __touch_watchdog();
@@ -281,7 +281,7 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
        duration = is_softlockup(touch_ts);
        if (unlikely(duration)) {
                /* only warn once */
-               if (__get_cpu_var(soft_watchdog_warn) == true)
+               if (__this_cpu_read(soft_watchdog_warn) == true)
                        return HRTIMER_RESTART;
 
                printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n",
@@ -296,9 +296,9 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
 
                if (softlockup_panic)
                        panic("softlockup: hung tasks");
-               __get_cpu_var(soft_watchdog_warn) = true;
+               __this_cpu_write(soft_watchdog_warn, true);
        } else
-               __get_cpu_var(soft_watchdog_warn) = false;
+               __this_cpu_write(soft_watchdog_warn, false);
 
        return HRTIMER_RESTART;
 }
index e785b0f2aea57f362f9528fb979f15716f7f2aa4..8ee6ec82f88a9cc2982bfcd73bc3bd86dcd490a8 100644 (file)
@@ -932,6 +932,38 @@ static void insert_work(struct cpu_workqueue_struct *cwq,
                wake_up_worker(gcwq);
 }
 
+/*
+ * Test whether @work is being queued from another work executing on the
+ * same workqueue.  This is rather expensive and should only be used from
+ * cold paths.
+ */
+static bool is_chained_work(struct workqueue_struct *wq)
+{
+       unsigned long flags;
+       unsigned int cpu;
+
+       for_each_gcwq_cpu(cpu) {
+               struct global_cwq *gcwq = get_gcwq(cpu);
+               struct worker *worker;
+               struct hlist_node *pos;
+               int i;
+
+               spin_lock_irqsave(&gcwq->lock, flags);
+               for_each_busy_worker(worker, i, pos, gcwq) {
+                       if (worker->task != current)
+                               continue;
+                       spin_unlock_irqrestore(&gcwq->lock, flags);
+                       /*
+                        * I'm @worker, no locking necessary.  See if @work
+                        * is headed to the same workqueue.
+                        */
+                       return worker->current_cwq->wq == wq;
+               }
+               spin_unlock_irqrestore(&gcwq->lock, flags);
+       }
+       return false;
+}
+
 static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
                         struct work_struct *work)
 {
@@ -943,7 +975,9 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
 
        debug_work_activate(work);
 
-       if (WARN_ON_ONCE(wq->flags & WQ_DYING))
+       /* if dying, only works from the same workqueue are allowed */
+       if (unlikely(wq->flags & WQ_DYING) &&
+           WARN_ON_ONCE(!is_chained_work(wq)))
                return;
 
        /* determine gcwq to use */
@@ -2936,11 +2970,35 @@ EXPORT_SYMBOL_GPL(__alloc_workqueue_key);
  */
 void destroy_workqueue(struct workqueue_struct *wq)
 {
+       unsigned int flush_cnt = 0;
        unsigned int cpu;
 
+       /*
+        * Mark @wq dying and drain all pending works.  Once WQ_DYING is
+        * set, only chain queueing is allowed.  IOW, only currently
+        * pending or running work items on @wq can queue further work
+        * items on it.  @wq is flushed repeatedly until it becomes empty.
+        * The number of flushing is detemined by the depth of chaining and
+        * should be relatively short.  Whine if it takes too long.
+        */
        wq->flags |= WQ_DYING;
+reflush:
        flush_workqueue(wq);
 
+       for_each_cwq_cpu(cpu, wq) {
+               struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
+
+               if (!cwq->nr_active && list_empty(&cwq->delayed_works))
+                       continue;
+
+               if (++flush_cnt == 10 ||
+                   (flush_cnt % 100 == 0 && flush_cnt <= 1000))
+                       printk(KERN_WARNING "workqueue %s: flush on "
+                              "destruction isn't complete after %u tries\n",
+                              wq->name, flush_cnt);
+               goto reflush;
+       }
+
        /*
         * wq list is used to freeze wq, remove from list after
         * flushing is complete in case freeze races us.
index 5d7a4802c5623c00056159735bf73d17165ba476..b66b2bd67952ea5ac3aaa2f3805a5a1b08f4c85e 100644 (file)
@@ -33,6 +33,22 @@ int hex_to_bin(char ch)
 }
 EXPORT_SYMBOL(hex_to_bin);
 
+/**
+ * hex2bin - convert an ascii hexadecimal string to its binary representation
+ * @dst: binary result
+ * @src: ascii hexadecimal string
+ * @count: result length
+ */
+void hex2bin(u8 *dst, const char *src, size_t count)
+{
+       while (count--) {
+               *dst = hex_to_bin(*src++) << 4;
+               *dst += hex_to_bin(*src++);
+               dst++;
+       }
+}
+EXPORT_SYMBOL(hex2bin);
+
 /**
  * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
  * @buf: data blob to dump
index 604678d7d06d9b101feafb31da72654d5f618500..28f2c33c6b537ac07f5d2692fe08b0d48a8dae91 100644 (file)
@@ -72,18 +72,16 @@ EXPORT_SYMBOL(percpu_counter_set);
 void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
 {
        s64 count;
-       s32 *pcount;
 
        preempt_disable();
-       pcount = this_cpu_ptr(fbc->counters);
-       count = *pcount + amount;
+       count = __this_cpu_read(*fbc->counters) + amount;
        if (count >= batch || count <= -batch) {
                spin_lock(&fbc->lock);
                fbc->count += count;
-               *pcount = 0;
+               __this_cpu_write(*fbc->counters, 0);
                spin_unlock(&fbc->lock);
        } else {
-               *pcount = count;
+               __this_cpu_write(*fbc->counters, count);
        }
        preempt_enable();
 }
index 02ba91230b99269f45beea6387c165e042800347..3dd4984bdef849c4a172c5e2d5d6f2d230137f8b 100644 (file)
@@ -293,12 +293,8 @@ static void *pcpu_mem_alloc(size_t size)
 
        if (size <= PAGE_SIZE)
                return kzalloc(size, GFP_KERNEL);
-       else {
-               void *ptr = vmalloc(size);
-               if (ptr)
-                       memset(ptr, 0, size);
-               return ptr;
-       }
+       else
+               return vzalloc(size);
 }
 
 /**
index 6107f2380e08282f980e7cca5dafb279ccb519b8..264037449f080a9247d247d9a18e401a25ab932a 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -829,12 +829,12 @@ static void init_reap_node(int cpu)
 
 static void next_reap_node(void)
 {
-       int node = __get_cpu_var(slab_reap_node);
+       int node = __this_cpu_read(slab_reap_node);
 
        node = next_node(node, node_online_map);
        if (unlikely(node >= MAX_NUMNODES))
                node = first_node(node_online_map);
-       __get_cpu_var(slab_reap_node) = node;
+       __this_cpu_write(slab_reap_node, node);
 }
 
 #else
@@ -1012,7 +1012,7 @@ static void __drain_alien_cache(struct kmem_cache *cachep,
  */
 static void reap_alien(struct kmem_cache *cachep, struct kmem_list3 *l3)
 {
-       int node = __get_cpu_var(slab_reap_node);
+       int node = __this_cpu_read(slab_reap_node);
 
        if (l3->alien) {
                struct array_cache *ac = l3->alien[node];
@@ -1293,7 +1293,7 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
                 * anything expensive but will only modify reap_work
                 * and reschedule the timer.
                */
-               cancel_rearming_delayed_work(&per_cpu(slab_reap_work, cpu));
+               cancel_delayed_work_sync(&per_cpu(slab_reap_work, cpu));
                /* Now the cache_reaper is guaranteed to be not running. */
                per_cpu(slab_reap_work, cpu).work.func = NULL;
                break;
@@ -3653,11 +3653,18 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
 EXPORT_SYMBOL(kmem_cache_alloc);
 
 #ifdef CONFIG_TRACING
-void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags)
+void *
+kmem_cache_alloc_trace(size_t size, struct kmem_cache *cachep, gfp_t flags)
 {
-       return __cache_alloc(cachep, flags, __builtin_return_address(0));
+       void *ret;
+
+       ret = __cache_alloc(cachep, flags, __builtin_return_address(0));
+
+       trace_kmalloc(_RET_IP_, ret,
+                     size, slab_buffer_size(cachep), flags);
+       return ret;
 }
-EXPORT_SYMBOL(kmem_cache_alloc_notrace);
+EXPORT_SYMBOL(kmem_cache_alloc_trace);
 #endif
 
 #ifdef CONFIG_NUMA
@@ -3675,31 +3682,32 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
 EXPORT_SYMBOL(kmem_cache_alloc_node);
 
 #ifdef CONFIG_TRACING
-void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep,
-                                   gfp_t flags,
-                                   int nodeid)
+void *kmem_cache_alloc_node_trace(size_t size,
+                                 struct kmem_cache *cachep,
+                                 gfp_t flags,
+                                 int nodeid)
 {
-       return __cache_alloc_node(cachep, flags, nodeid,
+       void *ret;
+
+       ret = __cache_alloc_node(cachep, flags, nodeid,
                                  __builtin_return_address(0));
+       trace_kmalloc_node(_RET_IP_, ret,
+                          size, slab_buffer_size(cachep),
+                          flags, nodeid);
+       return ret;
 }
-EXPORT_SYMBOL(kmem_cache_alloc_node_notrace);
+EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
 #endif
 
 static __always_inline void *
 __do_kmalloc_node(size_t size, gfp_t flags, int node, void *caller)
 {
        struct kmem_cache *cachep;
-       void *ret;
 
        cachep = kmem_find_general_cachep(size, flags);
        if (unlikely(ZERO_OR_NULL_PTR(cachep)))
                return cachep;
-       ret = kmem_cache_alloc_node_notrace(cachep, flags, node);
-
-       trace_kmalloc_node((unsigned long) caller, ret,
-                          size, cachep->buffer_size, flags, node);
-
-       return ret;
+       return kmem_cache_alloc_node_trace(size, cachep, flags, node);
 }
 
 #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_TRACING)
index a2fe1727ed859de71be8c769e3376b3749f442a4..008cd743a36a58cf0cec803bcef707d0329a3aa3 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -28,6 +28,8 @@
 #include <linux/math64.h>
 #include <linux/fault-inject.h>
 
+#include <trace/events/kmem.h>
+
 /*
  * Lock order:
  *   1. slab_lock(page)
@@ -1774,11 +1776,21 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
 EXPORT_SYMBOL(kmem_cache_alloc);
 
 #ifdef CONFIG_TRACING
-void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags)
+void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
+{
+       void *ret = slab_alloc(s, gfpflags, NUMA_NO_NODE, _RET_IP_);
+       trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags);
+       return ret;
+}
+EXPORT_SYMBOL(kmem_cache_alloc_trace);
+
+void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
 {
-       return slab_alloc(s, gfpflags, NUMA_NO_NODE, _RET_IP_);
+       void *ret = kmalloc_order(size, flags, order);
+       trace_kmalloc(_RET_IP_, ret, size, PAGE_SIZE << order, flags);
+       return ret;
 }
-EXPORT_SYMBOL(kmem_cache_alloc_notrace);
+EXPORT_SYMBOL(kmalloc_order_trace);
 #endif
 
 #ifdef CONFIG_NUMA
@@ -1794,13 +1806,17 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
 EXPORT_SYMBOL(kmem_cache_alloc_node);
 
 #ifdef CONFIG_TRACING
-void *kmem_cache_alloc_node_notrace(struct kmem_cache *s,
+void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
                                    gfp_t gfpflags,
-                                   int node)
+                                   int node, size_t size)
 {
-       return slab_alloc(s, gfpflags, node, _RET_IP_);
+       void *ret = slab_alloc(s, gfpflags, node, _RET_IP_);
+
+       trace_kmalloc_node(_RET_IP_, ret,
+                          size, s->size, gfpflags, node);
+       return ret;
 }
-EXPORT_SYMBOL(kmem_cache_alloc_node_notrace);
+EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
 #endif
 #endif
 
index 8f62f17ee1c726fec7fc683082b0807a15b848aa..312d728976f1661c4fa335a1ead46356b3bf091b 100644 (file)
@@ -167,35 +167,23 @@ static void refresh_zone_stat_thresholds(void)
 void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
                                int delta)
 {
-       struct per_cpu_pageset *pcp = this_cpu_ptr(zone->pageset);
-
-       s8 *p = pcp->vm_stat_diff + item;
+       struct per_cpu_pageset __percpu *pcp = zone->pageset;
+       s8 __percpu *p = pcp->vm_stat_diff + item;
        long x;
+       long t;
+
+       x = delta + __this_cpu_read(*p);
 
-       x = delta + *p;
+       t = __this_cpu_read(pcp->stat_threshold);
 
-       if (unlikely(x > pcp->stat_threshold || x < -pcp->stat_threshold)) {
+       if (unlikely(x > t || x < -t)) {
                zone_page_state_add(x, zone, item);
                x = 0;
        }
-       *p = x;
+       __this_cpu_write(*p, x);
 }
 EXPORT_SYMBOL(__mod_zone_page_state);
 
-/*
- * For an unknown interrupt state
- */
-void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
-                                       int delta)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       __mod_zone_page_state(zone, item, delta);
-       local_irq_restore(flags);
-}
-EXPORT_SYMBOL(mod_zone_page_state);
-
 /*
  * Optimized increment and decrement functions.
  *
@@ -221,16 +209,17 @@ EXPORT_SYMBOL(mod_zone_page_state);
  */
 void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
 {
-       struct per_cpu_pageset *pcp = this_cpu_ptr(zone->pageset);
-       s8 *p = pcp->vm_stat_diff + item;
+       struct per_cpu_pageset __percpu *pcp = zone->pageset;
+       s8 __percpu *p = pcp->vm_stat_diff + item;
+       s8 v, t;
 
-       (*p)++;
+       v = __this_cpu_inc_return(*p);
+       t = __this_cpu_read(pcp->stat_threshold);
+       if (unlikely(v > t)) {
+               s8 overstep = t >> 1;
 
-       if (unlikely(*p > pcp->stat_threshold)) {
-               int overstep = pcp->stat_threshold / 2;
-
-               zone_page_state_add(*p + overstep, zone, item);
-               *p = -overstep;
+               zone_page_state_add(v + overstep, zone, item);
+               __this_cpu_write(*p, -overstep);
        }
 }
 
@@ -242,16 +231,17 @@ EXPORT_SYMBOL(__inc_zone_page_state);
 
 void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
 {
-       struct per_cpu_pageset *pcp = this_cpu_ptr(zone->pageset);
-       s8 *p = pcp->vm_stat_diff + item;
-
-       (*p)--;
+       struct per_cpu_pageset __percpu *pcp = zone->pageset;
+       s8 __percpu *p = pcp->vm_stat_diff + item;
+       s8 v, t;
 
-       if (unlikely(*p < - pcp->stat_threshold)) {
-               int overstep = pcp->stat_threshold / 2;
+       v = __this_cpu_dec_return(*p);
+       t = __this_cpu_read(pcp->stat_threshold);
+       if (unlikely(v < - t)) {
+               s8 overstep = t >> 1;
 
-               zone_page_state_add(*p - overstep, zone, item);
-               *p = overstep;
+               zone_page_state_add(v - overstep, zone, item);
+               __this_cpu_write(*p, overstep);
        }
 }
 
@@ -261,6 +251,92 @@ void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
 }
 EXPORT_SYMBOL(__dec_zone_page_state);
 
+#ifdef CONFIG_CMPXCHG_LOCAL
+/*
+ * If we have cmpxchg_local support then we do not need to incur the overhead
+ * that comes with local_irq_save/restore if we use this_cpu_cmpxchg.
+ *
+ * mod_state() modifies the zone counter state through atomic per cpu
+ * operations.
+ *
+ * Overstep mode specifies how overstep should handled:
+ *     0       No overstepping
+ *     1       Overstepping half of threshold
+ *     -1      Overstepping minus half of threshold
+*/
+static inline void mod_state(struct zone *zone,
+       enum zone_stat_item item, int delta, int overstep_mode)
+{
+       struct per_cpu_pageset __percpu *pcp = zone->pageset;
+       s8 __percpu *p = pcp->vm_stat_diff + item;
+       long o, n, t, z;
+
+       do {
+               z = 0;  /* overflow to zone counters */
+
+               /*
+                * The fetching of the stat_threshold is racy. We may apply
+                * a counter threshold to the wrong the cpu if we get
+                * rescheduled while executing here. However, the following
+                * will apply the threshold again and therefore bring the
+                * counter under the threshold.
+                */
+               t = this_cpu_read(pcp->stat_threshold);
+
+               o = this_cpu_read(*p);
+               n = delta + o;
+
+               if (n > t || n < -t) {
+                       int os = overstep_mode * (t >> 1) ;
+
+                       /* Overflow must be added to zone counters */
+                       z = n + os;
+                       n = -os;
+               }
+       } while (this_cpu_cmpxchg(*p, o, n) != o);
+
+       if (z)
+               zone_page_state_add(z, zone, item);
+}
+
+void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
+                                       int delta)
+{
+       mod_state(zone, item, delta, 0);
+}
+EXPORT_SYMBOL(mod_zone_page_state);
+
+void inc_zone_state(struct zone *zone, enum zone_stat_item item)
+{
+       mod_state(zone, item, 1, 1);
+}
+
+void inc_zone_page_state(struct page *page, enum zone_stat_item item)
+{
+       mod_state(page_zone(page), item, 1, 1);
+}
+EXPORT_SYMBOL(inc_zone_page_state);
+
+void dec_zone_page_state(struct page *page, enum zone_stat_item item)
+{
+       mod_state(page_zone(page), item, -1, -1);
+}
+EXPORT_SYMBOL(dec_zone_page_state);
+#else
+/*
+ * Use interrupt disable to serialize counter updates
+ */
+void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
+                                       int delta)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __mod_zone_page_state(zone, item, delta);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(mod_zone_page_state);
+
 void inc_zone_state(struct zone *zone, enum zone_stat_item item)
 {
        unsigned long flags;
@@ -291,6 +367,7 @@ void dec_zone_page_state(struct page *page, enum zone_stat_item item)
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(dec_zone_page_state);
+#endif
 
 /*
  * Update the zone counters for one cpu.
@@ -1033,7 +1110,7 @@ static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
                break;
        case CPU_DOWN_PREPARE:
        case CPU_DOWN_PREPARE_FROZEN:
-               cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu));
+               cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
                per_cpu(vmstat_work, cpu).work.func = NULL;
                break;
        case CPU_DOWN_FAILED:
index 179e04bc99dd8ee00cd8bb9e1b10efa01bb48de4..38754fdb88babc634717cc2b0cd6eba297e119bd 100644 (file)
@@ -1607,7 +1607,7 @@ static void lec_arp_destroy(struct lec_priv *priv)
        struct lec_arp_table *entry;
        int i;
 
-       cancel_rearming_delayed_work(&priv->lec_arp_work);
+       cancel_delayed_work_sync(&priv->lec_arp_work);
 
        /*
         * Remove all entries
index 72d9b50109fc812bb161053d49a25a852cc792a3..02dc2cbcbe8652a0dd9e3b514cc96583da27842d 100644 (file)
@@ -923,7 +923,7 @@ void __netpoll_cleanup(struct netpoll *np)
 
                skb_queue_purge(&npinfo->arp_tx);
                skb_queue_purge(&npinfo->txq);
-               cancel_rearming_delayed_work(&npinfo->tx_work);
+               cancel_delayed_work_sync(&npinfo->tx_work);
 
                /* clean after last, unfinished work */
                __skb_queue_purge(&npinfo->txq);
index 6112a12578b26441c69038aaffa1cf90bd2f9b91..0c877a74e1f433699272953712458393045ff13c 100644 (file)
@@ -390,7 +390,7 @@ static int dsa_remove(struct platform_device *pdev)
        if (dst->link_poll_needed)
                del_timer_sync(&dst->link_poll_timer);
 
-       flush_scheduled_work();
+       flush_work_sync(&dst->link_poll_work);
 
        for (i = 0; i < dst->pd->nr_chips; i++) {
                struct dsa_switch *ds = dst->ds[i];
index c6f293639220a9aea901bdbb42a542233b643b64..22f7ad5101abb32d24af2d254dcd3528501d6553 100644 (file)
@@ -3430,7 +3430,7 @@ void ip_vs_control_cleanup(void)
 {
        EnterFunction(2);
        ip_vs_trash_cleanup();
-       cancel_rearming_delayed_work(&defense_work);
+       cancel_delayed_work_sync(&defense_work);
        cancel_work_sync(&defense_work.work);
        ip_vs_kill_estimator(&ip_vs_stats);
        unregister_sysctl_table(sysctl_header);
index dfcab5ac65af329149c637b3365751ce66999540..96549df836ee0ed5da8285960e88c47f9d6b107d 100644 (file)
@@ -770,7 +770,7 @@ static void xs_destroy(struct rpc_xprt *xprt)
 
        dprintk("RPC:       xs_destroy xprt %p\n", xprt);
 
-       cancel_rearming_delayed_work(&transport->connect_worker);
+       cancel_delayed_work_sync(&transport->connect_worker);
 
        xs_close(xprt);
        xs_free_peer_addresses(xprt);
index c5d5db54c009994c5945200b055e56b4869e7fff..e2741d23bab8c2343a928e402b063bcc0f251a0d 100644 (file)
@@ -7,3 +7,4 @@ pnmtologo
 bin2c
 unifdef
 ihex2fw
+recordmcount
index 4c72c1189479d9717b20f5bf9db0b8ebe116ad68..396da16aabf82e92498724274a2a6c661ddd7c4a 100644 (file)
@@ -200,6 +200,29 @@ quiet_cmd_gzip = GZIP    $@
 cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \
        (rm -f $@ ; false)
 
+# DTC
+# ---------------------------------------------------------------------------
+
+# Generate an assembly file to wrap the output of the device tree compiler
+quiet_cmd_dt_S_dtb= DTB    $@
+cmd_dt_S_dtb=                                          \
+(                                                      \
+       echo '\#include <asm-generic/vmlinux.lds.h>';   \
+       echo '.section .dtb.init.rodata,"a"';           \
+       echo '.balign STRUCT_ALIGNMENT';                \
+       echo '.global __dtb_$(*F)_begin';               \
+       echo '__dtb_$(*F)_begin:';                      \
+       echo '.incbin "$<" ';                           \
+       echo '__dtb_$(*F)_end:';                        \
+       echo '.global __dtb_$(*F)_end';                 \
+       echo '.balign STRUCT_ALIGNMENT';                \
+) > $@
+
+$(obj)/%.dtb.S: $(obj)/%.dtb
+       $(call cmd,dt_S_dtb)
+
+quiet_cmd_dtc = DTC     $@
+cmd_dtc = $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) $<
 
 # Bzip2
 # ---------------------------------------------------------------------------
index ea26b23de082b03cfa99483c52118f962a019a0e..c9a16abacab4a40a9dc9feb75c4096efc386b35e 100644 (file)
@@ -138,38 +138,36 @@ static void print_cmdline(void)
        printf("cmd_%s := %s\n\n", target, cmdline);
 }
 
-char * str_config  = NULL;
-int    size_config = 0;
-int    len_config  = 0;
+struct item {
+       struct item     *next;
+       unsigned int    len;
+       unsigned int    hash;
+       char            name[0];
+};
 
-/*
- * Grow the configuration string to a desired length.
- * Usually the first growth is plenty.
- */
-static void grow_config(int len)
-{
-       while (len_config + len > size_config) {
-               if (size_config == 0)
-                       size_config = 2048;
-               str_config = realloc(str_config, size_config *= 2);
-               if (str_config == NULL)
-                       { perror("fixdep:malloc"); exit(1); }
-       }
-}
+#define HASHSZ 256
+static struct item *hashtab[HASHSZ];
 
+static unsigned int strhash(const char *str, unsigned int sz)
+{
+       /* fnv32 hash */
+       unsigned int i, hash = 2166136261U;
 
+       for (i = 0; i < sz; i++)
+               hash = (hash ^ str[i]) * 0x01000193;
+       return hash;
+}
 
 /*
  * Lookup a value in the configuration string.
  */
-static int is_defined_config(const char * name, int len)
+static int is_defined_config(const char *name, int len, unsigned int hash)
 {
-       const char * pconfig;
-       const char * plast = str_config + len_config - len;
-       for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
-               if (pconfig[ -1] == '\n'
-               &&  pconfig[len] == '\n'
-               &&  !memcmp(pconfig, name, len))
+       struct item *aux;
+
+       for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {
+               if (aux->hash == hash && aux->len == len &&
+                   memcmp(aux->name, name, len) == 0)
                        return 1;
        }
        return 0;
@@ -178,13 +176,19 @@ static int is_defined_config(const char * name, int len)
 /*
  * Add a new value to the configuration string.
  */
-static void define_config(const char * name, int len)
+static void define_config(const char *name, int len, unsigned int hash)
 {
-       grow_config(len + 1);
+       struct item *aux = malloc(sizeof(*aux) + len);
 
-       memcpy(str_config+len_config, name, len);
-       len_config += len;
-       str_config[len_config++] = '\n';
+       if (!aux) {
+               perror("fixdep:malloc");
+               exit(1);
+       }
+       memcpy(aux->name, name, len);
+       aux->len = len;
+       aux->hash = hash;
+       aux->next = hashtab[hash % HASHSZ];
+       hashtab[hash % HASHSZ] = aux;
 }
 
 /*
@@ -192,40 +196,49 @@ static void define_config(const char * name, int len)
  */
 static void clear_config(void)
 {
-       len_config = 0;
-       define_config("", 0);
+       struct item *aux, *next;
+       unsigned int i;
+
+       for (i = 0; i < HASHSZ; i++) {
+               for (aux = hashtab[i]; aux; aux = next) {
+                       next = aux->next;
+                       free(aux);
+               }
+               hashtab[i] = NULL;
+       }
 }
 
 /*
  * Record the use of a CONFIG_* word.
  */
-static void use_config(char *m, int slen)
+static void use_config(const char *m, int slen)
 {
-       char s[PATH_MAX];
-       char *p;
+       unsigned int hash = strhash(m, slen);
+       int c, i;
 
-       if (is_defined_config(m, slen))
+       if (is_defined_config(m, slen, hash))
            return;
 
-       define_config(m, slen);
+       define_config(m, slen, hash);
 
-       memcpy(s, m, slen); s[slen] = 0;
-
-       for (p = s; p < s + slen; p++) {
-               if (*p == '_')
-                       *p = '/';
+       printf("    $(wildcard include/config/");
+       for (i = 0; i < slen; i++) {
+               c = m[i];
+               if (c == '_')
+                       c = '/';
                else
-                       *p = tolower((int)*p);
+                       c = tolower(c);
+               putchar(c);
        }
-       printf("    $(wildcard include/config/%s.h) \\\n", s);
+       printf(".h) \\\n");
 }
 
-static void parse_config_file(char *map, size_t len)
+static void parse_config_file(const char *map, size_t len)
 {
-       int *end = (int *) (map + len);
+       const int *end = (const int *) (map + len);
        /* start at +1, so that p can never be < map */
-       int *m   = (int *) map + 1;
-       char *p, *q;
+       const int *m   = (const int *) map + 1;
+       const char *p, *q;
 
        for (; m < end; m++) {
                if (*m == INT_CONF) { p = (char *) m  ; goto conf; }
@@ -265,7 +278,7 @@ static int strrcmp(char *s, char *sub)
        return memcmp(s + slen - sublen, sub, sublen);
 }
 
-static void do_config_file(char *filename)
+static void do_config_file(const char *filename)
 {
        struct stat st;
        int fd;
@@ -273,7 +286,7 @@ static void do_config_file(char *filename)
 
        fd = open(filename, O_RDONLY);
        if (fd < 0) {
-               fprintf(stderr, "fixdep: ");
+               fprintf(stderr, "fixdep: error opening config file: ");
                perror(filename);
                exit(2);
        }
@@ -344,11 +357,15 @@ static void print_deps(void)
 
        fd = open(depfile, O_RDONLY);
        if (fd < 0) {
-               fprintf(stderr, "fixdep: ");
+               fprintf(stderr, "fixdep: error opening depfile: ");
                perror(depfile);
                exit(2);
        }
-       fstat(fd, &st);
+       if (fstat(fd, &st) < 0) {
+                fprintf(stderr, "fixdep: error fstat'ing depfile: ");
+                perror(depfile);
+                exit(2);
+        }
        if (st.st_size == 0) {
                fprintf(stderr,"fixdep: %s is empty\n",depfile);
                close(fd);
index 6bb42e72e0e5f1fe7af925b29c17cd3f91e73556..3ab316e5231336cd528b1d591c517f42860ad721 100755 (executable)
@@ -6,7 +6,7 @@
 # and listed below so they are ignored.
 #
 # Usage:
-# syscallchk gcc gcc-options
+# checksyscalls.sh gcc gcc-options
 #
 
 ignore_list() {
@@ -204,5 +204,5 @@ sed -n -e '/^\#define/ s/[^_]*__NR_\([^[:space:]]*\).*/\
 \#endif/p' $1
 }
 
-(ignore_list && syscall_list ${srctree}/arch/x86/include/asm/unistd_32.h) | \
+(ignore_list && syscall_list $(dirname $0)/../arch/x86/include/asm/unistd_32.h) | \
 $* -E -x c - > /dev/null
index 55d7dc19dfe0525fa511134d84c42ce530a0e0da..156b20adb35163a603a533a90d73d7a7cc6c6ad0 100644 (file)
@@ -7,7 +7,7 @@
 // Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
 // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
-// Comments:
+// Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise
 // Options: -no_includes -include_headers
 
 virtual org
@@ -19,7 +19,7 @@ position p0,p;
 expression E;
 @@
 
-struct I s =@p0 { ... .fld@p = E, ...};
+struct I s =@p0 { ..., .fld@p = E, ...};
 
 @s@
 identifier I, s, r.fld;
@@ -27,7 +27,7 @@ position r.p0,p;
 expression E;
 @@
 
-struct I s =@p0 { ... .fld@p = E, ...};
+struct I s =@p0 { ..., .fld@p = E, ...};
 
 @script:python depends on org@
 p0 << r.p0;
index 9969d76d0f4b13027819522ca1cd4092afb40bd3..cdac6cfcce92cc8ab25304806fbff81991b51dad 100644 (file)
 // Options:
 
 virtual context
-virtual patch
 virtual org
 virtual report
 
-@initialize:python depends on !context && patch && !org && !report@
-
-import sys
-print >> sys.stderr, "This semantic patch does not support the 'patch' mode."
-
-@depends on patch@
-@@
-
-this_rule_should_never_matches();
-
-@ifm depends on !patch@
+@ifm@
 expression *E;
 statement S1,S2;
 position p1;
@@ -35,7 +24,7 @@ if@p1 ((E == NULL && ...) || ...) S1 else S2
 
 // The following two rules are separate, because both can match a single
 // expression in different ways
-@pr1 depends on !patch expression@
+@pr1 expression@
 expression *ifm.E;
 identifier f;
 position p1;
@@ -43,7 +32,7 @@ position p1;
 
  (E != NULL && ...) ? <+...E->f@p1...+> : ...
 
-@pr2 depends on !patch expression@
+@pr2 expression@
 expression *ifm.E;
 identifier f;
 position p2;
@@ -59,7 +48,7 @@ position p2;
 
 // For org and report modes
 
-@r depends on !context && !patch && (org || report) exists@
+@r depends on !context && (org || report) exists@
 expression subE <= ifm.E;
 expression *ifm.E;
 expression E1,E2;
@@ -99,7 +88,7 @@ if@p1 ((E == NULL && ...) || ...)
 }
 else S3
 
-@script:python depends on !context && !patch && !org && report@
+@script:python depends on !context && !org && report@
 p << r.p;
 p1 << ifm.p1;
 x << ifm.E;
@@ -109,7 +98,7 @@ msg="ERROR: %s is NULL but dereferenced." % (x)
 coccilib.report.print_report(p[0], msg)
 cocci.include_match(False)
 
-@script:python depends on !context && !patch && org && !report@
+@script:python depends on !context && org && !report@
 p << r.p;
 p1 << ifm.p1;
 x << ifm.E;
@@ -120,7 +109,7 @@ msg_safe=msg.replace("[","@(").replace("]",")")
 cocci.print_main(msg_safe,p)
 cocci.include_match(False)
 
-@s depends on !context && !patch && (org || report) exists@
+@s depends on !context && (org || report) exists@
 expression subE <= ifm.E;
 expression *ifm.E;
 expression E1,E2;
@@ -159,7 +148,7 @@ if@p1 ((E == NULL && ...) || ...)
 }
 else S3
 
-@script:python depends on !context && !patch && !org && report@
+@script:python depends on !context && !org && report@
 p << s.p;
 p1 << ifm.p1;
 x << ifm.E;
@@ -168,7 +157,7 @@ x << ifm.E;
 msg="ERROR: %s is NULL but dereferenced." % (x)
 coccilib.report.print_report(p[0], msg)
 
-@script:python depends on !context && !patch && org && !report@
+@script:python depends on !context && org && !report@
 p << s.p;
 p1 << ifm.p1;
 x << ifm.E;
@@ -180,7 +169,7 @@ cocci.print_main(msg_safe,p)
 
 // For context mode
 
-@depends on context && !patch && !org && !report exists@
+@depends on context && !org && !report exists@
 expression subE <= ifm.E;
 expression *ifm.E;
 expression E1,E2;
@@ -223,7 +212,7 @@ else S3
 // The following three rules are duplicates of ifm, pr1 and pr2 respectively.
 // It is need because the previous rule as already made a "change".
 
-@ifm1 depends on !patch@
+@ifm1@
 expression *E;
 statement S1,S2;
 position p1;
@@ -231,7 +220,7 @@ position p1;
 
 if@p1 ((E == NULL && ...) || ...) S1 else S2
 
-@pr11 depends on !patch expression@
+@pr11 expression@
 expression *ifm1.E;
 identifier f;
 position p1;
@@ -239,7 +228,7 @@ position p1;
 
  (E != NULL && ...) ? <+...E->f@p1...+> : ...
 
-@pr12 depends on !patch expression@
+@pr12 expression@
 expression *ifm1.E;
 identifier f;
 position p2;
@@ -253,7 +242,7 @@ position p2;
  sizeof(<+...E->f@p2...+>)
 )
 
-@depends on context && !patch && !org && !report exists@
+@depends on context && !org && !report exists@
 expression subE <= ifm1.E;
 expression *ifm1.E;
 expression E1,E2;
index 608d7fdb13e8d6ac901eaf99cc3b1b5df0a7cc95..a7c7c4b8e957311196f9b2eabef414ceaa144555 100755 (executable)
@@ -10,8 +10,10 @@ commands:
        --enable|-e option   Enable option
        --disable|-d option  Disable option
        --module|-m option   Turn option into a module
-       --set-str option value
-                            Set option to "value"
+       --set-str option string
+                            Set option to "string"
+       --set-val option value
+                            Set option to value
        --state|-s option    Print state of option (n,y,m,undef)
 
        --enable-after|-E beforeopt option
@@ -86,7 +88,7 @@ while [ "$1" != "" ] ; do
                B=$ARG
                shift 2
                ;;
-       --*)
+       -*)
                checkarg "$1"
                shift
                ;;
@@ -109,6 +111,11 @@ while [ "$1" != "" ] ; do
                shift
                ;;
 
+       --set-val)
+               set_var "CONFIG_$ARG" "CONFIG_$ARG=$1"
+               shift
+               ;;
+
        --state|-s)
                if grep -q "# CONFIG_$ARG is not set" $FN ; then
                        echo n
index 01cdb36fc5832653b665d738f0369a32689b2f2e..04a31c17639f84f3555389aa4d8980fe324d1e6a 100644 (file)
@@ -4,7 +4,7 @@ hostprogs-y     := dtc
 always         := $(hostprogs-y)
 
 dtc-objs       := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
-                  srcpos.o checks.o
+                  srcpos.o checks.o util.o
 dtc-objs       += dtc-lexer.lex.o dtc-parser.tab.o
 
 # Source files need to get at the userspace version of libfdt_env.h to compile
@@ -19,6 +19,7 @@ HOSTCFLAGS_fstree.o := $(HOSTCFLAGS_DTC)
 HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC)
 HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC)
 HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC)
+HOSTCFLAGS_util.o := $(HOSTCFLAGS_DTC)
 
 HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC)
 HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC)
index 95485796f253ffb0d2c413e50acf650fe397aece..a662a0044798f3b8f58fbd5f9011e82979f82bd2 100644 (file)
@@ -278,32 +278,112 @@ static void check_property_name_chars(struct check *c, struct node *dt,
 }
 PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
 
+#define DESCLABEL_FMT  "%s%s%s%s%s"
+#define DESCLABEL_ARGS(node,prop,mark)         \
+       ((mark) ? "value of " : ""),            \
+       ((prop) ? "'" : ""), \
+       ((prop) ? (prop)->name : ""), \
+       ((prop) ? "' in " : ""), (node)->fullpath
+
+static void check_duplicate_label(struct check *c, struct node *dt,
+                                 const char *label, struct node *node,
+                                 struct property *prop, struct marker *mark)
+{
+       struct node *othernode = NULL;
+       struct property *otherprop = NULL;
+       struct marker *othermark = NULL;
+
+       othernode = get_node_by_label(dt, label);
+
+       if (!othernode)
+               otherprop = get_property_by_label(dt, label, &othernode);
+       if (!othernode)
+               othermark = get_marker_label(dt, label, &othernode,
+                                              &otherprop);
+
+       if (!othernode)
+               return;
+
+       if ((othernode != node) || (otherprop != prop) || (othermark != mark))
+               FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT
+                    " and " DESCLABEL_FMT,
+                    label, DESCLABEL_ARGS(node, prop, mark),
+                    DESCLABEL_ARGS(othernode, otherprop, othermark));
+}
+
+static void check_duplicate_label_node(struct check *c, struct node *dt,
+                                      struct node *node)
+{
+       struct label *l;
+
+       for_each_label(node->labels, l)
+               check_duplicate_label(c, dt, l->label, node, NULL, NULL);
+}
+static void check_duplicate_label_prop(struct check *c, struct node *dt,
+                                      struct node *node, struct property *prop)
+{
+       struct marker *m = prop->val.markers;
+       struct label *l;
+
+       for_each_label(prop->labels, l)
+               check_duplicate_label(c, dt, l->label, node, prop, NULL);
+
+       for_each_marker_of_type(m, LABEL)
+               check_duplicate_label(c, dt, m->ref, node, prop, m);
+}
+CHECK(duplicate_label, NULL, check_duplicate_label_node,
+      check_duplicate_label_prop, NULL, ERROR);
+
 static void check_explicit_phandles(struct check *c, struct node *root,
-                                         struct node *node)
+                                   struct node *node, struct property *prop)
 {
-       struct property *prop;
+       struct marker *m;
        struct node *other;
        cell_t phandle;
 
-       prop = get_property(node, "linux,phandle");
-       if (! prop)
-               return; /* No phandle, that's fine */
+       if (!streq(prop->name, "phandle")
+           && !streq(prop->name, "linux,phandle"))
+               return;
 
        if (prop->val.len != sizeof(cell_t)) {
-               FAIL(c, "%s has bad length (%d) linux,phandle property",
-                    node->fullpath, prop->val.len);
+               FAIL(c, "%s has bad length (%d) %s property",
+                    node->fullpath, prop->val.len, prop->name);
+               return;
+       }
+
+       m = prop->val.markers;
+       for_each_marker_of_type(m, REF_PHANDLE) {
+               assert(m->offset == 0);
+               if (node != get_node_by_ref(root, m->ref))
+                       /* "Set this node's phandle equal to some
+                        * other node's phandle".  That's nonsensical
+                        * by construction. */ {
+                       FAIL(c, "%s in %s is a reference to another node",
+                            prop->name, node->fullpath);
+                       return;
+               }
+               /* But setting this node's phandle equal to its own
+                * phandle is allowed - that means allocate a unique
+                * phandle for this node, even if it's not otherwise
+                * referenced.  The value will be filled in later, so
+                * no further checking for now. */
                return;
        }
 
        phandle = propval_cell(prop);
+
        if ((phandle == 0) || (phandle == -1)) {
-               FAIL(c, "%s has invalid linux,phandle value 0x%x",
-                    node->fullpath, phandle);
+               FAIL(c, "%s has bad value (0x%x) in %s property",
+                    node->fullpath, phandle, prop->name);
                return;
        }
 
+       if (node->phandle && (node->phandle != phandle))
+               FAIL(c, "%s has %s property which replaces existing phandle information",
+                    node->fullpath, prop->name);
+
        other = get_node_by_phandle(root, phandle);
-       if (other) {
+       if (other && (other != node)) {
                FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
                     node->fullpath, phandle, other->fullpath);
                return;
@@ -311,7 +391,7 @@ static void check_explicit_phandles(struct check *c, struct node *root,
 
        node->phandle = phandle;
 }
-NODE_CHECK(explicit_phandles, NULL, ERROR);
+PROP_CHECK(explicit_phandles, NULL, ERROR);
 
 static void check_name_properties(struct check *c, struct node *root,
                                  struct node *node)
@@ -549,6 +629,9 @@ static struct check *check_table[] = {
        &duplicate_node_names, &duplicate_property_names,
        &node_name_chars, &node_name_format, &property_name_chars,
        &name_is_string, &name_properties,
+
+       &duplicate_label,
+
        &explicit_phandles,
        &phandle_references, &path_references,
 
index a627bbee91d42d5acf6d59558b44d70d582397ce..e866ea5166ac40a140092c4987170b48a04ef398 100644 (file)
@@ -18,7 +18,7 @@
  *                                                                   USA
  */
 
-%option noyywrap noinput nounput yylineno
+%option noyywrap nounput noinput never-interactive
 
 %x INCLUDE
 %x BYTESTRING
@@ -38,6 +38,13 @@ LINECOMMENT  "//".*\n
 #include "srcpos.h"
 #include "dtc-parser.tab.h"
 
+YYLTYPE yylloc;
+
+/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
+#define        YY_USER_ACTION \
+       { \
+               srcpos_update(&yylloc, yytext, yyleng); \
+       }
 
 /*#define LEXDEBUG     1*/
 
@@ -47,15 +54,10 @@ LINECOMMENT "//".*\n
 #define DPRINT(fmt, ...)       do { } while (0)
 #endif
 
-static int dts_version; /* = 0 */
+static int dts_version = 1;
 
-#define BEGIN_DEFAULT()        if (dts_version == 0) { \
-                               DPRINT("<INITIAL>\n"); \
-                               BEGIN(INITIAL); \
-                       } else { \
-                               DPRINT("<V1>\n"); \
+#define BEGIN_DEFAULT()                DPRINT("<V1>\n"); \
                                BEGIN(V1); \
-                       }
 
 static void push_input_file(const char *filename);
 static int pop_input_file(void);
@@ -75,18 +77,13 @@ static int pop_input_file(void);
                }
 
 <*>{STRING}    {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("String: %s\n", yytext);
                        yylval.data = data_copy_escape_string(yytext+1,
                                        yyleng-2);
-                       yylloc.first_line = yylineno;
                        return DT_STRING;
                }
 
 <*>"/dts-v1/"  {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Keyword: /dts-v1/\n");
                        dts_version = 1;
                        BEGIN_DEFAULT();
@@ -94,106 +91,57 @@ static int pop_input_file(void);
                }
 
 <*>"/memreserve/"      {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Keyword: /memreserve/\n");
                        BEGIN_DEFAULT();
                        return DT_MEMRESERVE;
                }
 
 <*>{LABEL}:    {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Label: %s\n", yytext);
-                       yylval.labelref = strdup(yytext);
+                       yylval.labelref = xstrdup(yytext);
                        yylval.labelref[yyleng-1] = '\0';
                        return DT_LABEL;
                }
 
-<INITIAL>[bodh]# {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
-                       if (*yytext == 'b')
-                               yylval.cbase = 2;
-                       else if (*yytext == 'o')
-                               yylval.cbase = 8;
-                       else if (*yytext == 'd')
-                               yylval.cbase = 10;
-                       else
-                               yylval.cbase = 16;
-                       DPRINT("Base: %d\n", yylval.cbase);
-                       return DT_BASE;
-               }
-
-<INITIAL>[0-9a-fA-F]+  {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
-                       yylval.literal = strdup(yytext);
-                       DPRINT("Literal: '%s'\n", yylval.literal);
-                       return DT_LEGACYLITERAL;
-               }
-
 <V1>[0-9]+|0[xX][0-9a-fA-F]+      {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
-                       yylval.literal = strdup(yytext);
+                       yylval.literal = xstrdup(yytext);
                        DPRINT("Literal: '%s'\n", yylval.literal);
                        return DT_LITERAL;
                }
 
-\&{LABEL}      {       /* label reference */
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
+<*>\&{LABEL}   {       /* label reference */
                        DPRINT("Ref: %s\n", yytext+1);
-                       yylval.labelref = strdup(yytext+1);
+                       yylval.labelref = xstrdup(yytext+1);
                        return DT_REF;
                }
 
-"&{/"{PATHCHAR}+\}     {       /* new-style path reference */
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
+<*>"&{/"{PATHCHAR}+\}  {       /* new-style path reference */
                        yytext[yyleng-1] = '\0';
                        DPRINT("Ref: %s\n", yytext+2);
-                       yylval.labelref = strdup(yytext+2);
-                       return DT_REF;
-               }
-
-<INITIAL>"&/"{PATHCHAR}+ {     /* old-style path reference */
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
-                       DPRINT("Ref: %s\n", yytext+1);
-                       yylval.labelref = strdup(yytext+1);
+                       yylval.labelref = xstrdup(yytext+2);
                        return DT_REF;
                }
 
 <BYTESTRING>[0-9a-fA-F]{2} {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        yylval.byte = strtol(yytext, NULL, 16);
                        DPRINT("Byte: %02x\n", (int)yylval.byte);
                        return DT_BYTE;
                }
 
 <BYTESTRING>"]"        {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("/BYTESTRING\n");
                        BEGIN_DEFAULT();
                        return ']';
                }
 
 <PROPNODENAME>{PROPNODECHAR}+ {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("PropNodeName: %s\n", yytext);
-                       yylval.propnodename = strdup(yytext);
+                       yylval.propnodename = xstrdup(yytext);
                        BEGIN_DEFAULT();
                        return DT_PROPNODENAME;
                }
 
 "/incbin/"     {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Binary Include\n");
                        return DT_INCBIN;
                }
@@ -203,8 +151,6 @@ static int pop_input_file(void);
 <*>{LINECOMMENT}+ /* eat C++-style comments */
 
 <*>.           {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Char: %c (\\x%02x)\n", yytext[0],
                                (unsigned)yytext[0]);
                        if (yytext[0] == '[') {
@@ -221,100 +167,25 @@ static int pop_input_file(void);
 
 %%
 
-
-/*
- * Stack of nested include file contexts.
- */
-
-struct incl_file {
-       struct dtc_file *file;
-       YY_BUFFER_STATE yy_prev_buf;
-       int yy_prev_lineno;
-       struct incl_file *prev;
-};
-
-static struct incl_file *incl_file_stack;
-
-
-/*
- * Detect infinite include recursion.
- */
-#define MAX_INCLUDE_DEPTH      (100)
-
-static int incl_depth = 0;
-
-
 static void push_input_file(const char *filename)
 {
-       struct incl_file *incl_file;
-       struct dtc_file *newfile;
-       struct search_path search, *searchptr = NULL;
-
        assert(filename);
 
-       if (incl_depth++ >= MAX_INCLUDE_DEPTH)
-               die("Includes nested too deeply");
-
-       if (srcpos_file) {
-               search.dir = srcpos_file->dir;
-               search.next = NULL;
-               search.prev = NULL;
-               searchptr = &search;
-       }
-
-       newfile = dtc_open_file(filename, searchptr);
+       srcfile_push(filename);
 
-       incl_file = xmalloc(sizeof(struct incl_file));
+       yyin = current_srcfile->f;
 
-       /*
-        * Save current context.
-        */
-       incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
-       incl_file->yy_prev_lineno = yylineno;
-       incl_file->file = srcpos_file;
-       incl_file->prev = incl_file_stack;
-
-       incl_file_stack = incl_file;
-
-       /*
-        * Establish new context.
-        */
-       srcpos_file = newfile;
-       yylineno = 1;
-       yyin = newfile->file;
-       yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+       yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
 }
 
 
 static int pop_input_file(void)
 {
-       struct incl_file *incl_file;
-
-       if (incl_file_stack == 0)
+       if (srcfile_pop() == 0)
                return 0;
 
-       dtc_close_file(srcpos_file);
-
-       /*
-        * Pop.
-        */
-       --incl_depth;
-       incl_file = incl_file_stack;
-       incl_file_stack = incl_file->prev;
-
-       /*
-        * Recover old context.
-        */
-       yy_delete_buffer(YY_CURRENT_BUFFER);
-       yy_switch_to_buffer(incl_file->yy_prev_buf);
-       yylineno = incl_file->yy_prev_lineno;
-       srcpos_file = incl_file->file;
-       yyin = incl_file->file ? incl_file->file->file : NULL;
-
-       /*
-        * Free old state.
-        */
-       free(incl_file);
+       yypop_buffer_state();
+       yyin = current_srcfile->f;
 
        return 1;
 }
index e27cc636e326ed58c92bd122c15c272b48414610..50c4420b4b2c9c6894d66bc7df30b0203637ec4f 100644 (file)
@@ -170,20 +170,7 @@ extern FILE *yyin, *yyout;
 #define EOB_ACT_END_OF_FILE 1
 #define EOB_ACT_LAST_MATCH 2
 
-    /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
-     *       access to the local variable yy_act. Since yyless() is a macro, it would break
-     *       existing scanners that call yyless() from OUTSIDE yylex. 
-     *       One obvious solution it to make yy_act a global. I tried that, and saw
-     *       a 5% performance hit in a non-yylineno scanner, because yy_act is
-     *       normally declared as a register variable-- so it is not worth it.
-     */
-    #define  YY_LESS_LINENO(n) \
-            do { \
-                int yyl;\
-                for ( yyl = n; yyl < yyleng; ++yyl )\
-                    if ( yytext[yyl] == '\n' )\
-                        --yylineno;\
-            }while(0)
+    #define YY_LESS_LINENO(n)
     
 /* Return all but the first "n" matched characters back to the input stream. */
 #define yyless(n) \
@@ -385,8 +372,8 @@ static void yy_fatal_error (yyconst char msg[]  );
        *yy_cp = '\0'; \
        (yy_c_buf_p) = yy_cp;
 
-#define YY_NUM_RULES 20
-#define YY_END_OF_BUFFER 21
+#define YY_NUM_RULES 17
+#define YY_END_OF_BUFFER 18
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -394,20 +381,19 @@ struct yy_trans_info
        flex_int32_t yy_verify;
        flex_int32_t yy_nxt;
        };
-static yyconst flex_int16_t yy_accept[104] =
+static yyconst flex_int16_t yy_accept[94] =
     {   0,
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-       21,   19,   16,   16,   19,   19,   19,    7,    7,   19,
-        7,   19,   19,   19,   19,   13,   14,   14,   19,    8,
-        8,   16,    0,    2,    0,    0,    9,    0,    0,    0,
-        0,    0,    0,    7,    7,    5,    0,    6,    0,   12,
-       12,   14,   14,    8,    0,   11,    9,    0,    0,    0,
-        0,   18,    0,    0,    0,    0,    8,    0,   17,    0,
-        0,    0,    0,    0,   10,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    3,   15,
+       18,   16,   13,   13,   16,   16,   16,   16,   16,   16,
+       16,   10,   11,   11,    6,    6,   13,    0,    2,    0,
+        7,    0,    0,    0,    0,    0,    0,    0,    5,    0,
+        9,    9,   11,   11,    6,    0,    7,    0,    0,    0,
+        0,   15,    0,    0,    0,    0,    6,    0,   14,    0,
+        0,    0,    0,    0,    8,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    3,   12,
         0,    0,    0,    0,    0,    0,    0,    0,    1,    0,
-
         0,    4,    0
+
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -416,16 +402,16 @@ static yyconst flex_int32_t yy_ec[256] =
         2,    2,    2,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    2,    1,    4,    5,    1,    1,    6,    1,    1,
-        1,    7,    8,    8,    9,    8,   10,   11,   12,   13,
-       13,   13,   13,   13,   13,   13,   13,   14,    1,    1,
-        1,    1,    8,    8,   15,   15,   15,   15,   15,   15,
-       16,   16,   16,   16,   16,   16,   16,   16,   16,   16,
-       16,   16,   16,   16,   16,   16,   16,   17,   16,   16,
-        1,   18,   19,    1,   16,    1,   15,   20,   21,   22,
-
-       23,   15,   16,   24,   25,   16,   16,   26,   27,   28,
-       24,   16,   16,   29,   30,   31,   32,   33,   16,   17,
-       16,   16,   34,    1,   35,    1,    1,    1,    1,    1,
+        1,    7,    5,    5,    8,    5,    9,   10,   11,   12,
+       12,   12,   12,   12,   12,   12,   12,   13,    1,    1,
+        1,    1,    5,    5,   14,   14,   14,   14,   14,   14,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   16,   15,   15,
+        1,   17,   18,    1,   15,    1,   14,   19,   20,   21,
+
+       22,   14,   15,   15,   23,   15,   15,   24,   25,   26,
+       15,   15,   15,   27,   28,   29,   30,   31,   15,   16,
+       15,   15,   32,    1,   33,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -442,136 +428,114 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[36] =
+static yyconst flex_int32_t yy_meta[34] =
     {   0,
-        1,    1,    1,    1,    2,    1,    2,    2,    2,    3,
-        4,    4,    4,    5,    6,    7,    7,    1,    1,    6,
-        6,    6,    6,    7,    7,    7,    7,    7,    7,    7,
-        7,    7,    7,    8,    1
+        1,    1,    1,    1,    2,    1,    2,    2,    3,    4,
+        4,    4,    5,    6,    7,    7,    1,    1,    6,    6,
+        6,    6,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    8,    1
     } ;
 
-static yyconst flex_int16_t yy_base[117] =
+static yyconst flex_int16_t yy_base[106] =
     {   0,
-        0,    0,   30,    0,   44,    0,   67,    0,   97,  105,
-      302,  303,   35,   44,   40,   94,  112,    0,  129,  152,
-      296,  295,  159,    0,  176,  303,    0,  116,   95,  165,
-       49,   46,  102,  303,  296,    0,    0,  288,  290,  293,
-      264,  266,  270,    0,    0,  303,    0,  303,  264,  303,
-        0,    0,  195,  101,    0,    0,    0,    0,  284,  125,
-      277,  265,  225,  230,  216,  218,    0,  202,  224,  221,
-      217,  107,  196,  188,  303,  206,  179,  186,  178,  185,
-      183,  162,  161,  150,  169,  160,  145,  125,  303,  303,
-      137,  109,  190,  103,  203,  167,  108,  197,  303,  123,
-
-       29,  303,  303,  215,  221,  226,  229,  234,  240,  246,
-      250,  257,  265,  270,  275,  282
+        0,    0,  237,  236,   25,    0,   47,    0,   30,   71,
+      244,  247,   82,   84,   84,  211,   95,  229,  218,    0,
+      111,  247,    0,   84,   83,   95,  106,   86,  247,  237,
+        0,  230,  231,  234,  207,  209,  212,  220,  247,  206,
+      247,  218,    0,  106,  116,    0,    0,    0,  223,   89,
+      226,  219,  199,  206,  200,  204,    0,  190,  213,  212,
+      202,   91,  178,  161,  247,  172,  144,  150,  140,  130,
+      140,  124,  128,  120,  138,  137,  123,  122,  247,  247,
+      134,  114,  132,   86,  135,  125,   90,  136,  247,   97,
+       29,  247,  247,  153,  156,  161,  165,  170,  176,  180,
+
+      187,  195,  200,  205,  212
     } ;
 
-static yyconst flex_int16_t yy_def[117] =
+static yyconst flex_int16_t yy_def[106] =
     {   0,
-      103,    1,    1,    3,    3,    5,  103,    7,    3,    3,
-      103,  103,  103,  103,  104,  105,  103,  106,  103,   19,
-       19,   20,  103,  107,   20,  103,  108,  109,  105,  103,
-      103,  103,  104,  103,  104,  110,  111,  103,  112,  113,
-      103,  103,  103,  106,   19,  103,   20,  103,  103,  103,
-       20,  108,  109,  103,  114,  110,  111,  115,  112,  112,
-      113,  103,  103,  103,  103,  103,  114,  115,  103,  103,
-      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
-      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
-      103,  103,  103,  103,  103,  116,  103,  116,  103,  116,
-
-      103,  103,    0,  103,  103,  103,  103,  103,  103,  103,
-      103,  103,  103,  103,  103,  103
+       93,    1,    1,    1,    1,    5,   93,    7,    1,    1,
+       93,   93,   93,   93,   94,   95,   93,   96,   17,   97,
+       96,   93,   98,   99,   93,   93,   93,   94,   93,   94,
+      100,   93,  101,  102,   93,   93,   93,   96,   93,   93,
+       93,   96,   98,   99,   93,  103,  100,  104,  101,  101,
+      102,   93,   93,   93,   93,   93,  103,  104,   93,   93,
+       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
+       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
+       93,   93,   93,   93,   93,  105,   93,  105,   93,  105,
+       93,   93,    0,   93,   93,   93,   93,   93,   93,   93,
+
+       93,   93,   93,   93,   93
     } ;
 
-static yyconst flex_int16_t yy_nxt[339] =
+static yyconst flex_int16_t yy_nxt[281] =
     {   0,
-       12,   13,   14,   15,   12,   16,   12,   12,   12,   17,
-       18,   18,   18,   12,   19,   20,   20,   12,   12,   21,
-       19,   21,   19,   22,   20,   20,   20,   20,   20,   20,
-       20,   20,   20,   12,   12,   12,   32,   32,  102,   23,
-       12,   12,   12,   34,   20,   32,   32,   32,   32,   20,
-       20,   20,   20,   20,   24,   24,   24,   35,   25,   54,
-       54,   54,   26,   25,   25,   25,   25,   12,   13,   14,
-       15,   27,   12,   27,   27,   27,   23,   27,   27,   27,
-       12,   28,   28,   28,   12,   12,   28,   28,   28,   28,
-       28,   28,   28,   28,   28,   28,   28,   28,   28,   28,
-
-       12,   12,   29,   36,  103,   34,   17,   30,   31,   31,
-       29,   54,   54,   54,   17,   30,   31,   31,   39,   35,
-       52,   40,   52,   52,   52,  103,   78,   38,   38,   46,
-      101,   60,   79,   41,   69,   97,   42,   94,   43,   45,
-       45,   45,   46,   45,   47,   47,   93,   92,   45,   45,
-       45,   45,   47,   47,   47,   47,   47,   47,   47,   47,
-       47,   47,   47,   47,   47,   39,   47,   91,   40,   90,
-       99,   47,   47,   47,   47,   54,   54,   54,   89,   88,
-       41,   55,   87,   49,  100,   43,   51,   51,   51,   86,
-       51,   95,   95,   96,   85,   51,   51,   51,   51,   52,
-
-       99,   52,   52,   52,   95,   95,   96,   84,   46,   83,
-       82,   81,   39,   79,  100,   33,   33,   33,   33,   33,
-       33,   33,   33,   37,   80,   77,   37,   37,   37,   44,
-       40,   44,   50,   76,   50,   52,   75,   52,   74,   52,
-       52,   53,   73,   53,   53,   53,   53,   56,   56,   56,
-       72,   56,   56,   57,   71,   57,   57,   59,   59,   59,
-       59,   59,   59,   59,   59,   61,   61,   61,   61,   61,
-       61,   61,   61,   67,   70,   67,   68,   68,   68,   62,
-       68,   68,   98,   98,   98,   98,   98,   98,   98,   98,
-       60,   66,   65,   64,   63,   62,   60,   58,  103,   48,
-
-       48,  103,   11,  103,  103,  103,  103,  103,  103,  103,
-      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
-      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
-      103,  103,  103,  103,  103,  103,  103,  103
+       12,   13,   14,   15,   12,   16,   12,   12,   17,   12,
+       12,   12,   12,   18,   18,   18,   12,   12,   18,   18,
+       18,   18,   18,   18,   18,   18,   18,   18,   18,   18,
+       18,   12,   12,   19,   20,   20,   20,   92,   21,   25,
+       26,   26,   22,   21,   21,   21,   21,   12,   13,   14,
+       15,   23,   16,   23,   23,   19,   23,   23,   23,   12,
+       24,   24,   24,   12,   12,   24,   24,   24,   24,   24,
+       24,   24,   24,   24,   24,   24,   24,   24,   12,   12,
+       25,   26,   26,   27,   27,   27,   27,   29,   43,   29,
+       43,   43,   45,   45,   45,   50,   39,   59,   46,   93,
+
+       30,   33,   30,   34,   45,   45,   45,   27,   27,   68,
+       43,   91,   43,   43,   69,   35,   87,   36,   39,   37,
+       42,   42,   42,   39,   42,   45,   45,   45,   89,   42,
+       42,   42,   42,   85,   85,   86,   85,   85,   86,   89,
+       84,   90,   83,   82,   81,   80,   79,   78,   77,   76,
+       75,   74,   90,   28,   28,   28,   28,   28,   28,   28,
+       28,   31,   31,   31,   38,   38,   38,   38,   41,   73,
+       41,   43,   72,   43,   71,   43,   43,   44,   33,   44,
+       44,   44,   44,   47,   69,   47,   47,   49,   49,   49,
+       49,   49,   49,   49,   49,   51,   51,   51,   51,   51,
+
+       51,   51,   51,   57,   70,   57,   58,   58,   58,   67,
+       58,   58,   88,   88,   88,   88,   88,   88,   88,   88,
+       34,   66,   65,   64,   63,   62,   61,   60,   52,   50,
+       39,   56,   39,   55,   54,   53,   52,   50,   48,   93,
+       40,   39,   32,   93,   19,   19,   11,   93,   93,   93,
+       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
+       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
+       93,   93,   93,   93,   93,   93,   93,   93,   93,   93
     } ;
 
-static yyconst flex_int16_t yy_chk[339] =
+static yyconst flex_int16_t yy_chk[281] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    3,   13,   13,  101,    3,
-        3,    3,    3,   15,    3,   14,   14,   32,   32,    3,
-        3,    3,    3,    3,    5,    5,    5,   15,    5,   31,
-       31,   31,    5,    5,    5,    5,    5,    7,    7,    7,
+        1,    1,    1,    5,    5,    5,    5,   91,    5,    9,
+        9,    9,    5,    5,    5,    5,    5,    7,    7,    7,
         7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
         7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
         7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
-
-        7,    7,    9,   16,   29,   33,    9,    9,    9,    9,
-       10,   54,   54,   54,   10,   10,   10,   10,   17,   33,
-       28,   17,   28,   28,   28,  100,   72,   16,   29,   28,
-       97,   60,   72,   17,   60,   94,   17,   92,   17,   19,
-       19,   19,   19,   19,   19,   19,   91,   88,   19,   19,
-       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
-       19,   19,   20,   20,   20,   23,   20,   87,   23,   86,
-       96,   20,   20,   20,   20,   30,   30,   30,   85,   84,
-       23,   30,   83,   23,   96,   23,   25,   25,   25,   82,
-       25,   93,   93,   93,   81,   25,   25,   25,   25,   53,
-
-       98,   53,   53,   53,   95,   95,   95,   80,   53,   79,
-       78,   77,   76,   74,   98,  104,  104,  104,  104,  104,
-      104,  104,  104,  105,   73,   71,  105,  105,  105,  106,
-       70,  106,  107,   69,  107,  108,   68,  108,   66,  108,
-      108,  109,   65,  109,  109,  109,  109,  110,  110,  110,
-       64,  110,  110,  111,   63,  111,  111,  112,  112,  112,
-      112,  112,  112,  112,  112,  113,  113,  113,  113,  113,
-      113,  113,  113,  114,   62,  114,  115,  115,  115,   61,
-      115,  115,  116,  116,  116,  116,  116,  116,  116,  116,
-       59,   49,   43,   42,   41,   40,   39,   38,   35,   22,
-
-       21,   11,  103,  103,  103,  103,  103,  103,  103,  103,
-      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
-      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
-      103,  103,  103,  103,  103,  103,  103,  103
+       10,   10,   10,   13,   13,   14,   14,   15,   24,   28,
+       24,   24,   25,   25,   25,   50,   24,   50,   25,   90,
+
+       15,   17,   28,   17,   26,   26,   26,   27,   27,   62,
+       44,   87,   44,   44,   62,   17,   84,   17,   44,   17,
+       21,   21,   21,   21,   21,   45,   45,   45,   86,   21,
+       21,   21,   21,   83,   83,   83,   85,   85,   85,   88,
+       82,   86,   81,   78,   77,   76,   75,   74,   73,   72,
+       71,   70,   88,   94,   94,   94,   94,   94,   94,   94,
+       94,   95,   95,   95,   96,   96,   96,   96,   97,   69,
+       97,   98,   68,   98,   67,   98,   98,   99,   66,   99,
+       99,   99,   99,  100,   64,  100,  100,  101,  101,  101,
+      101,  101,  101,  101,  101,  102,  102,  102,  102,  102,
+
+      102,  102,  102,  103,   63,  103,  104,  104,  104,   61,
+      104,  104,  105,  105,  105,  105,  105,  105,  105,  105,
+       60,   59,   58,   56,   55,   54,   53,   52,   51,   49,
+       42,   40,   38,   37,   36,   35,   34,   33,   32,   30,
+       19,   18,   16,   11,    4,    3,   93,   93,   93,   93,
+       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
+       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
+       93,   93,   93,   93,   93,   93,   93,   93,   93,   93
     } ;
 
-/* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[21] =
-    {   0,
-1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 
-    0,     };
-
 static yy_state_type yy_last_accepting_state;
 static char *yy_last_accepting_cpos;
 
@@ -616,6 +580,13 @@ char *yytext;
 #include "srcpos.h"
 #include "dtc-parser.tab.h"
 
+YYLTYPE yylloc;
+
+/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
+#define        YY_USER_ACTION \
+       { \
+               srcpos_update(&yylloc, yytext, yyleng); \
+       }
 
 /*#define LEXDEBUG     1*/
 
@@ -625,19 +596,14 @@ char *yytext;
 #define DPRINT(fmt, ...)       do { } while (0)
 #endif
 
-static int dts_version; /* = 0 */
+static int dts_version = 1;
 
-#define BEGIN_DEFAULT()        if (dts_version == 0) { \
-                               DPRINT("<INITIAL>\n"); \
-                               BEGIN(INITIAL); \
-                       } else { \
-                               DPRINT("<V1>\n"); \
+#define BEGIN_DEFAULT()                DPRINT("<V1>\n"); \
                                BEGIN(V1); \
-                       }
 
 static void push_input_file(const char *filename);
 static int pop_input_file(void);
-#line 641 "dtc-lexer.lex.c"
+#line 607 "dtc-lexer.lex.c"
 
 #define INITIAL 0
 #define INCLUDE 1
@@ -826,9 +792,9 @@ YY_DECL
        register char *yy_cp, *yy_bp;
        register int yy_act;
     
-#line 64 "dtc-lexer.l"
+#line 66 "dtc-lexer.l"
 
-#line 832 "dtc-lexer.lex.c"
+#line 798 "dtc-lexer.lex.c"
 
        if ( !(yy_init) )
                {
@@ -881,35 +847,21 @@ yy_match:
                        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                                {
                                yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 104 )
+                               if ( yy_current_state >= 94 )
                                        yy_c = yy_meta[(unsigned int) yy_c];
                                }
                        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
                        ++yy_cp;
                        }
-               while ( yy_base[yy_current_state] != 303 );
+               while ( yy_current_state != 93 );
+               yy_cp = (yy_last_accepting_cpos);
+               yy_current_state = (yy_last_accepting_state);
 
 yy_find_action:
                yy_act = yy_accept[yy_current_state];
-               if ( yy_act == 0 )
-                       { /* have to back up */
-                       yy_cp = (yy_last_accepting_cpos);
-                       yy_current_state = (yy_last_accepting_state);
-                       yy_act = yy_accept[yy_current_state];
-                       }
 
                YY_DO_BEFORE_ACTION;
 
-               if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
-                       {
-                       int yyl;
-                       for ( yyl = 0; yyl < yyleng; ++yyl )
-                               if ( yytext[yyl] == '\n' )
-                                          
-    yylineno++;
-;
-                       }
-
 do_action:     /* This label is used only to access EOF actions. */
 
                switch ( yy_act )
@@ -924,7 +876,7 @@ do_action:  /* This label is used only to access EOF actions. */
 case 1:
 /* rule 1 can match eol */
 YY_RULE_SETUP
-#line 65 "dtc-lexer.l"
+#line 67 "dtc-lexer.l"
 {
                        char *name = strchr(yytext, '\"') + 1;
                        yytext[yyleng-1] = '\0';
@@ -936,7 +888,7 @@ case YY_STATE_EOF(INCLUDE):
 case YY_STATE_EOF(BYTESTRING):
 case YY_STATE_EOF(PROPNODENAME):
 case YY_STATE_EOF(V1):
-#line 71 "dtc-lexer.l"
+#line 73 "dtc-lexer.l"
 {
                        if (!pop_input_file()) {
                                yyterminate();
@@ -946,23 +898,18 @@ case YY_STATE_EOF(V1):
 case 2:
 /* rule 2 can match eol */
 YY_RULE_SETUP
-#line 77 "dtc-lexer.l"
+#line 79 "dtc-lexer.l"
 {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("String: %s\n", yytext);
                        yylval.data = data_copy_escape_string(yytext+1,
                                        yyleng-2);
-                       yylloc.first_line = yylineno;
                        return DT_STRING;
                }
        YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 87 "dtc-lexer.l"
+#line 86 "dtc-lexer.l"
 {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Keyword: /dts-v1/\n");
                        dts_version = 1;
                        BEGIN_DEFAULT();
@@ -971,10 +918,8 @@ YY_RULE_SETUP
        YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 96 "dtc-lexer.l"
+#line 93 "dtc-lexer.l"
 {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Keyword: /memreserve/\n");
                        BEGIN_DEFAULT();
                        return DT_MEMRESERVE;
@@ -982,158 +927,100 @@ YY_RULE_SETUP
        YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 104 "dtc-lexer.l"
+#line 99 "dtc-lexer.l"
 {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Label: %s\n", yytext);
-                       yylval.labelref = strdup(yytext);
+                       yylval.labelref = xstrdup(yytext);
                        yylval.labelref[yyleng-1] = '\0';
                        return DT_LABEL;
                }
        YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 113 "dtc-lexer.l"
-{
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
-                       if (*yytext == 'b')
-                               yylval.cbase = 2;
-                       else if (*yytext == 'o')
-                               yylval.cbase = 8;
-                       else if (*yytext == 'd')
-                               yylval.cbase = 10;
-                       else
-                               yylval.cbase = 16;
-                       DPRINT("Base: %d\n", yylval.cbase);
-                       return DT_BASE;
-               }
-       YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 128 "dtc-lexer.l"
+#line 106 "dtc-lexer.l"
 {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
-                       yylval.literal = strdup(yytext);
-                       DPRINT("Literal: '%s'\n", yylval.literal);
-                       return DT_LEGACYLITERAL;
-               }
-       YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 136 "dtc-lexer.l"
-{
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
-                       yylval.literal = strdup(yytext);
+                       yylval.literal = xstrdup(yytext);
                        DPRINT("Literal: '%s'\n", yylval.literal);
                        return DT_LITERAL;
                }
        YY_BREAK
-case 9:
+case 7:
 YY_RULE_SETUP
-#line 144 "dtc-lexer.l"
+#line 112 "dtc-lexer.l"
 {      /* label reference */
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Ref: %s\n", yytext+1);
-                       yylval.labelref = strdup(yytext+1);
+                       yylval.labelref = xstrdup(yytext+1);
                        return DT_REF;
                }
        YY_BREAK
-case 10:
+case 8:
 YY_RULE_SETUP
-#line 152 "dtc-lexer.l"
+#line 118 "dtc-lexer.l"
 {      /* new-style path reference */
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        yytext[yyleng-1] = '\0';
                        DPRINT("Ref: %s\n", yytext+2);
-                       yylval.labelref = strdup(yytext+2);
+                       yylval.labelref = xstrdup(yytext+2);
                        return DT_REF;
                }
        YY_BREAK
-case 11:
-YY_RULE_SETUP
-#line 161 "dtc-lexer.l"
-{      /* old-style path reference */
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
-                       DPRINT("Ref: %s\n", yytext+1);
-                       yylval.labelref = strdup(yytext+1);
-                       return DT_REF;
-               }
-       YY_BREAK
-case 12:
+case 9:
 YY_RULE_SETUP
-#line 169 "dtc-lexer.l"
+#line 125 "dtc-lexer.l"
 {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        yylval.byte = strtol(yytext, NULL, 16);
                        DPRINT("Byte: %02x\n", (int)yylval.byte);
                        return DT_BYTE;
                }
        YY_BREAK
-case 13:
+case 10:
 YY_RULE_SETUP
-#line 177 "dtc-lexer.l"
+#line 131 "dtc-lexer.l"
 {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("/BYTESTRING\n");
                        BEGIN_DEFAULT();
                        return ']';
                }
        YY_BREAK
-case 14:
+case 11:
 YY_RULE_SETUP
-#line 185 "dtc-lexer.l"
+#line 137 "dtc-lexer.l"
 {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("PropNodeName: %s\n", yytext);
-                       yylval.propnodename = strdup(yytext);
+                       yylval.propnodename = xstrdup(yytext);
                        BEGIN_DEFAULT();
                        return DT_PROPNODENAME;
                }
        YY_BREAK
-case 15:
+case 12:
 YY_RULE_SETUP
-#line 194 "dtc-lexer.l"
+#line 144 "dtc-lexer.l"
 {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Binary Include\n");
                        return DT_INCBIN;
                }
        YY_BREAK
-case 16:
-/* rule 16 can match eol */
+case 13:
+/* rule 13 can match eol */
 YY_RULE_SETUP
-#line 201 "dtc-lexer.l"
+#line 149 "dtc-lexer.l"
 /* eat whitespace */
        YY_BREAK
-case 17:
-/* rule 17 can match eol */
+case 14:
+/* rule 14 can match eol */
 YY_RULE_SETUP
-#line 202 "dtc-lexer.l"
+#line 150 "dtc-lexer.l"
 /* eat C-style comments */
        YY_BREAK
-case 18:
-/* rule 18 can match eol */
+case 15:
+/* rule 15 can match eol */
 YY_RULE_SETUP
-#line 203 "dtc-lexer.l"
+#line 151 "dtc-lexer.l"
 /* eat C++-style comments */
        YY_BREAK
-case 19:
+case 16:
 YY_RULE_SETUP
-#line 205 "dtc-lexer.l"
+#line 153 "dtc-lexer.l"
 {
-                       yylloc.file = srcpos_file;
-                       yylloc.first_line = yylineno;
                        DPRINT("Char: %c (\\x%02x)\n", yytext[0],
                                (unsigned)yytext[0]);
                        if (yytext[0] == '[') {
@@ -1148,12 +1035,12 @@ YY_RULE_SETUP
                        return yytext[0];
                }
        YY_BREAK
-case 20:
+case 17:
 YY_RULE_SETUP
-#line 222 "dtc-lexer.l"
+#line 168 "dtc-lexer.l"
 ECHO;
        YY_BREAK
-#line 1157 "dtc-lexer.lex.c"
+#line 1044 "dtc-lexer.lex.c"
 
        case YY_END_OF_BUFFER:
                {
@@ -1218,7 +1105,8 @@ ECHO;
 
                        else
                                {
-                               yy_cp = (yy_c_buf_p);
+                               yy_cp = (yy_last_accepting_cpos);
+                               yy_current_state = (yy_last_accepting_state);
                                goto yy_find_action;
                                }
                        }
@@ -1443,7 +1331,7 @@ static int yy_get_next_buffer (void)
                while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                        {
                        yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 104 )
+                       if ( yy_current_state >= 94 )
                                yy_c = yy_meta[(unsigned int) yy_c];
                        }
                yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1471,11 +1359,11 @@ static int yy_get_next_buffer (void)
        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                {
                yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 104 )
+               if ( yy_current_state >= 94 )
                        yy_c = yy_meta[(unsigned int) yy_c];
                }
        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-       yy_is_jam = (yy_current_state == 103);
+       yy_is_jam = (yy_current_state == 93);
 
        return yy_is_jam ? 0 : yy_current_state;
 }
@@ -1550,11 +1438,6 @@ static int yy_get_next_buffer (void)
        *(yy_c_buf_p) = '\0';   /* preserve yytext */
        (yy_hold_char) = *++(yy_c_buf_p);
 
-       if ( c == '\n' )
-                  
-    yylineno++;
-;
-
        return c;
 }
 #endif /* ifndef YY_NO_INPUT */
@@ -1669,10 +1552,6 @@ static void yy_load_buffer_state  (void)
        yyfree((void *) b  );
 }
 
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-    
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
  * such as during a yyrestart() or at EOF.
@@ -1696,7 +1575,7 @@ extern int isatty (int );
         b->yy_bs_column = 0;
     }
 
-        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+        b->yy_is_interactive = 0;
     
        errno = oerrno;
 }
@@ -2025,9 +1904,6 @@ static int yy_init_globals (void)
      * This function is called from yylex_destroy(), so don't allocate here.
      */
 
-    /* We do not touch yylineno unless the option is enabled. */
-    yylineno =  1;
-    
     (yy_buffer_stack) = 0;
     (yy_buffer_stack_top) = 0;
     (yy_buffer_stack_max) = 0;
@@ -2120,104 +1996,29 @@ void yyfree (void * ptr )
 
 #define YYTABLES_NAME "yytables"
 
-#line 222 "dtc-lexer.l"
-
-
-
-
-/*
- * Stack of nested include file contexts.
- */
-
-struct incl_file {
-       struct dtc_file *file;
-       YY_BUFFER_STATE yy_prev_buf;
-       int yy_prev_lineno;
-       struct incl_file *prev;
-};
-
-static struct incl_file *incl_file_stack;
+#line 168 "dtc-lexer.l"
 
 
-/*
- * Detect infinite include recursion.
- */
-#define MAX_INCLUDE_DEPTH      (100)
-
-static int incl_depth = 0;
-
 
 static void push_input_file(const char *filename)
 {
-       struct incl_file *incl_file;
-       struct dtc_file *newfile;
-       struct search_path search, *searchptr = NULL;
-
        assert(filename);
 
-       if (incl_depth++ >= MAX_INCLUDE_DEPTH)
-               die("Includes nested too deeply");
-
-       if (srcpos_file) {
-               search.dir = srcpos_file->dir;
-               search.next = NULL;
-               search.prev = NULL;
-               searchptr = &search;
-       }
-
-       newfile = dtc_open_file(filename, searchptr);
+       srcfile_push(filename);
 
-       incl_file = xmalloc(sizeof(struct incl_file));
+       yyin = current_srcfile->f;
 
-       /*
-        * Save current context.
-        */
-       incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
-       incl_file->yy_prev_lineno = yylineno;
-       incl_file->file = srcpos_file;
-       incl_file->prev = incl_file_stack;
-
-       incl_file_stack = incl_file;
-
-       /*
-        * Establish new context.
-        */
-       srcpos_file = newfile;
-       yylineno = 1;
-       yyin = newfile->file;
-       yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
+       yypush_buffer_state(yy_create_buffer(yyin,YY_BUF_SIZE));
 }
 
 
 static int pop_input_file(void)
 {
-       struct incl_file *incl_file;
-
-       if (incl_file_stack == 0)
+       if (srcfile_pop() == 0)
                return 0;
 
-       dtc_close_file(srcpos_file);
-
-       /*
-        * Pop.
-        */
-       --incl_depth;
-       incl_file = incl_file_stack;
-       incl_file_stack = incl_file->prev;
-
-       /*
-        * Recover old context.
-        */
-       yy_delete_buffer(YY_CURRENT_BUFFER);
-       yy_switch_to_buffer(incl_file->yy_prev_buf);
-       yylineno = incl_file->yy_prev_lineno;
-       srcpos_file = incl_file->file;
-       yyin = incl_file->file ? incl_file->file->file : NULL;
-
-       /*
-        * Free old state.
-        */
-       free(incl_file);
+       yypop_buffer_state();
+       yyin = current_srcfile->f;
 
        return 1;
 }
index 27129377e5d217dce3ca2a4501f9c36a6b181071..9be2eea18a304d8ca28cd812b6610fc546cfc00d 100644 (file)
@@ -1,24 +1,23 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
 
-/* Skeleton implementation for Bison's Yacc-like parsers in C
+/* A Bison parser, made by GNU Bison 2.4.1.  */
 
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
+   
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-
+   
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
@@ -29,7 +28,7 @@
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-
+   
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
@@ -47,7 +46,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.3"
+#define YYBISON_VERSION "2.4.1"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
 /* Pure parsers.  */
 #define YYPURE 0
 
-/* Using locations.  */
-#define YYLSP_NEEDED 1
-
+/* Push parsers.  */
+#define YYPUSH 0
 
+/* Pull parsers.  */
+#define YYPULL 1
 
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     DT_V1 = 258,
-     DT_MEMRESERVE = 259,
-     DT_PROPNODENAME = 260,
-     DT_LITERAL = 261,
-     DT_LEGACYLITERAL = 262,
-     DT_BASE = 263,
-     DT_BYTE = 264,
-     DT_STRING = 265,
-     DT_LABEL = 266,
-     DT_REF = 267,
-     DT_INCBIN = 268
-   };
-#endif
-/* Tokens.  */
-#define DT_V1 258
-#define DT_MEMRESERVE 259
-#define DT_PROPNODENAME 260
-#define DT_LITERAL 261
-#define DT_LEGACYLITERAL 262
-#define DT_BASE 263
-#define DT_BYTE 264
-#define DT_STRING 265
-#define DT_LABEL 266
-#define DT_REF 267
-#define DT_INCBIN 268
-
+/* Using locations.  */
+#define YYLSP_NEEDED 0
 
 
 
 /* Copy the first part of user declarations.  */
-#line 23 "dtc-parser.y"
+
+/* Line 189 of yacc.c  */
+#line 21 "dtc-parser.y"
 
 #include <stdio.h>
 
 #include "dtc.h"
 #include "srcpos.h"
 
+YYLTYPE yylloc;
+
 extern int yylex(void);
+extern void print_error(char const *fmt, ...);
+extern void yyerror(char const *s);
 
 extern struct boot_info *the_boot_info;
 extern int treesource_error;
@@ -111,6 +87,9 @@ extern int treesource_error;
 static unsigned long long eval_literal(const char *s, int base, int bits);
 
 
+/* Line 189 of yacc.c  */
+#line 92 "dtc-parser.tab.c"
+
 /* Enabling traces.  */
 #ifndef YYDEBUG
 # define YYDEBUG 0
@@ -129,10 +108,35 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
 # define YYTOKEN_TABLE 0
 #endif
 
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     DT_V1 = 258,
+     DT_MEMRESERVE = 259,
+     DT_PROPNODENAME = 260,
+     DT_LITERAL = 261,
+     DT_BASE = 262,
+     DT_BYTE = 263,
+     DT_STRING = 264,
+     DT_LABEL = 265,
+     DT_REF = 266,
+     DT_INCBIN = 267
+   };
+#endif
+
+
+
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 37 "dtc-parser.y"
 {
+
+/* Line 214 of yacc.c  */
+#line 39 "dtc-parser.y"
+
        char *propnodename;
        char *literal;
        char *labelref;
@@ -147,34 +151,23 @@ typedef union YYSTYPE
        struct node *node;
        struct node *nodelist;
        struct reserve_info *re;
-}
-/* Line 187 of yacc.c.  */
-#line 153 "dtc-parser.tab.c"
-       YYSTYPE;
+
+
+
+/* Line 214 of yacc.c  */
+#line 159 "dtc-parser.tab.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
-typedef struct YYLTYPE
-{
-  int first_line;
-  int first_column;
-  int last_line;
-  int last_column;
-} YYLTYPE;
-# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
-# define YYLTYPE_IS_DECLARED 1
-# define YYLTYPE_IS_TRIVIAL 1
 #endif
 
 
 /* Copy the second part of user declarations.  */
 
 
-/* Line 216 of yacc.c.  */
-#line 178 "dtc-parser.tab.c"
+/* Line 264 of yacc.c  */
+#line 171 "dtc-parser.tab.c"
 
 #ifdef short
 # undef short
@@ -249,14 +242,14 @@ typedef short int yytype_int16;
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static int
-YYID (int i)
+YYID (int yyi)
 #else
 static int
-YYID (i)
-    int i;
+YYID (yyi)
+    int yyi;
 #endif
 {
-  return i;
+  return yyi;
 }
 #endif
 
@@ -332,15 +325,13 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 
 #if (! defined yyoverflow \
      && (! defined __cplusplus \
-        || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
-            && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+        || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
 
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  yytype_int16 yyss;
-  YYSTYPE yyvs;
-    YYLTYPE yyls;
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
 };
 
 /* The size of the maximum gap between one aligned stack and the next.  */
@@ -349,8 +340,8 @@ union yyalloc
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
 # define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
-      + 2 * YYSTACK_GAP_MAXIMUM)
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
 
 /* Copy COUNT objects from FROM to TO.  The source and destination do
    not overlap.  */
@@ -375,12 +366,12 @@ union yyalloc
    elements in the stack, and YYPTR gives the new location of the
    stack.  Advance YYPTR to a properly aligned location for the next
    stack.  */
-# define YYSTACK_RELOCATE(Stack)                                       \
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)                          \
     do                                                                 \
       {                                                                        \
        YYSIZE_T yynewbytes;                                            \
-       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
-       Stack = &yyptr->Stack;                                          \
+       YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+       Stack = &yyptr->Stack_alloc;                                    \
        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
        yyptr += yynewbytes / sizeof (*yyptr);                          \
       }                                                                        \
@@ -389,22 +380,22 @@ union yyalloc
 #endif
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  9
+#define YYFINAL  4
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   73
+#define YYLAST   56
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  27
+#define YYNTOKENS  25
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  20
+#define YYNNTS  16
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  45
+#define YYNRULES  39
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  76
+#define YYNSTATES  67
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   268
+#define YYMAXUTOK   267
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -416,15 +407,15 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      24,    26,     2,     2,    25,    15,     2,    16,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,    14,
-      20,    19,    21,     2,     2,     2,     2,     2,     2,     2,
+      22,    24,     2,     2,    23,     2,     2,    14,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,    13,
+      18,    17,    19,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    22,     2,    23,     2,     2,     2,     2,     2,     2,
+       2,    20,     2,    21,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    17,     2,    18,     2,     2,     2,     2,
+       2,     2,     2,    15,     2,    16,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -438,7 +429,7 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13
+       5,     6,     7,     8,     9,    10,    11,    12
 };
 
 #if YYDEBUG
@@ -446,41 +437,37 @@ static const yytype_uint8 yytranslate[] =
    YYRHS.  */
 static const yytype_uint8 yyprhs[] =
 {
-       0,     0,     3,     8,    11,    12,    15,    21,    22,    25,
-      27,    34,    36,    38,    41,    47,    48,    51,    57,    61,
-      64,    69,    74,    77,    87,    93,    96,    97,   100,   103,
-     104,   107,   110,   113,   114,   116,   118,   121,   122,   125,
-     128,   129,   132,   135,   139,   140
+       0,     0,     3,     8,     9,    12,    17,    20,    22,    25,
+      29,    33,    39,    40,    43,    48,    51,    54,    57,    62,
+      67,    70,    80,    86,    89,    90,    93,    96,    97,   100,
+     103,   106,   108,   109,   112,   115,   116,   119,   122,   125
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      28,     0,    -1,     3,    14,    29,    34,    -1,    31,    34,
-      -1,    -1,    30,    29,    -1,    46,     4,    33,    33,    14,
-      -1,    -1,    32,    31,    -1,    30,    -1,    46,     4,    33,
-      15,    33,    14,    -1,     6,    -1,     7,    -1,    16,    35,
-      -1,    17,    36,    44,    18,    14,    -1,    -1,    36,    37,
-      -1,    46,     5,    19,    38,    14,    -1,    46,     5,    14,
-      -1,    39,    10,    -1,    39,    20,    40,    21,    -1,    39,
-      22,    43,    23,    -1,    39,    12,    -1,    39,    13,    24,
-      10,    25,    33,    25,    33,    26,    -1,    39,    13,    24,
-      10,    26,    -1,    38,    11,    -1,    -1,    38,    25,    -1,
-      39,    11,    -1,    -1,    40,    42,    -1,    40,    12,    -1,
-      40,    11,    -1,    -1,     8,    -1,     6,    -1,    41,     7,
-      -1,    -1,    43,     9,    -1,    43,    11,    -1,    -1,    45,
-      44,    -1,    45,    37,    -1,    46,     5,    35,    -1,    -1,
-      11,    -1
+      26,     0,    -1,     3,    13,    27,    30,    -1,    -1,    28,
+      27,    -1,     4,    29,    29,    13,    -1,    10,    28,    -1,
+       6,    -1,    14,    31,    -1,    30,    14,    31,    -1,    30,
+      11,    31,    -1,    15,    32,    39,    16,    13,    -1,    -1,
+      32,    33,    -1,     5,    17,    34,    13,    -1,     5,    13,
+      -1,    10,    33,    -1,    35,     9,    -1,    35,    18,    36,
+      19,    -1,    35,    20,    38,    21,    -1,    35,    11,    -1,
+      35,    12,    22,     9,    23,    29,    23,    29,    24,    -1,
+      35,    12,    22,     9,    24,    -1,    34,    10,    -1,    -1,
+      34,    23,    -1,    35,    10,    -1,    -1,    36,    37,    -1,
+      36,    11,    -1,    36,    10,    -1,     6,    -1,    -1,    38,
+       8,    -1,    38,    10,    -1,    -1,    40,    39,    -1,    40,
+      33,    -1,     5,    31,    -1,    10,    40,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,    89,    89,    93,   101,   104,   111,   119,   122,   129,
-     133,   140,   144,   151,   158,   166,   169,   176,   180,   187,
-     191,   195,   199,   203,   220,   231,   239,   242,   246,   254,
-     257,   261,   266,   274,   277,   281,   285,   293,   296,   300,
-     308,   311,   315,   323,   331,   334
+       0,    86,    86,    95,    98,   105,   109,   117,   124,   128,
+     132,   145,   153,   156,   163,   167,   171,   179,   183,   187,
+     191,   195,   212,   222,   230,   233,   237,   245,   248,   252,
+     257,   264,   272,   275,   279,   287,   290,   294,   302,   306
 };
 #endif
 
@@ -490,13 +477,12 @@ static const yytype_uint16 yyrline[] =
 static const char *const yytname[] =
 {
   "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE",
-  "DT_PROPNODENAME", "DT_LITERAL", "DT_LEGACYLITERAL", "DT_BASE",
-  "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF", "DT_INCBIN", "';'", "'-'",
-  "'/'", "'{'", "'}'", "'='", "'<'", "'>'", "'['", "']'", "'('", "','",
-  "')'", "$accept", "sourcefile", "memreserves", "memreserve",
-  "v0_memreserves", "v0_memreserve", "addr", "devicetree", "nodedef",
-  "proplist", "propdef", "propdata", "propdataprefix", "celllist",
-  "cellbase", "cellval", "bytestring", "subnodes", "subnode", "label", 0
+  "DT_PROPNODENAME", "DT_LITERAL", "DT_BASE", "DT_BYTE", "DT_STRING",
+  "DT_LABEL", "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='",
+  "'<'", "'>'", "'['", "']'", "'('", "','", "')'", "$accept", "sourcefile",
+  "memreserves", "memreserve", "addr", "devicetree", "nodedef", "proplist",
+  "propdef", "propdata", "propdataprefix", "celllist", "cellval",
+  "bytestring", "subnodes", "subnode", 0
 };
 #endif
 
@@ -506,29 +492,27 @@ static const char *const yytname[] =
 static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,    59,    45,    47,   123,   125,    61,
-      60,    62,    91,    93,    40,    44,    41
+     265,   266,   267,    59,    47,   123,   125,    61,    60,    62,
+      91,    93,    40,    44,    41
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    27,    28,    28,    29,    29,    30,    31,    31,    32,
-      32,    33,    33,    34,    35,    36,    36,    37,    37,    38,
-      38,    38,    38,    38,    38,    38,    39,    39,    39,    40,
-      40,    40,    40,    41,    41,    42,    42,    43,    43,    43,
-      44,    44,    44,    45,    46,    46
+       0,    25,    26,    27,    27,    28,    28,    29,    30,    30,
+      30,    31,    32,    32,    33,    33,    33,    34,    34,    34,
+      34,    34,    34,    34,    35,    35,    35,    36,    36,    36,
+      36,    37,    38,    38,    38,    39,    39,    39,    40,    40
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     4,     2,     0,     2,     5,     0,     2,     1,
-       6,     1,     1,     2,     5,     0,     2,     5,     3,     2,
-       4,     4,     2,     9,     5,     2,     0,     2,     2,     0,
-       2,     2,     2,     0,     1,     1,     2,     0,     2,     2,
-       0,     2,     2,     3,     0,     1
+       0,     2,     4,     0,     2,     4,     2,     1,     2,     3,
+       3,     5,     0,     2,     4,     2,     2,     2,     4,     4,
+       2,     9,     5,     2,     0,     2,     2,     0,     2,     2,
+       2,     1,     0,     2,     2,     0,     2,     2,     2,     2
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -536,86 +520,79 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       7,     0,    45,     0,     9,     0,     7,     0,     4,     1,
-       0,     3,     8,     0,     0,     4,     0,    15,    13,    11,
-      12,     0,     2,     5,     0,    40,     0,     0,     0,    16,
-       0,    40,     0,     0,     6,     0,    42,    41,     0,    10,
-      14,    18,    26,    43,     0,     0,    25,    17,    27,    19,
-      28,    22,     0,    29,    37,     0,    33,     0,     0,    35,
-      34,    32,    31,    20,     0,    30,    38,    39,    21,     0,
-      24,    36,     0,     0,     0,    23
+       0,     0,     0,     3,     1,     0,     0,     0,     3,     7,
+       0,     6,     0,     2,     4,     0,    12,     8,     0,     0,
+       5,    35,    10,     9,     0,     0,    13,     0,    35,    15,
+      24,    38,    16,    39,     0,    37,    36,     0,     0,    11,
+      23,    14,    25,    17,    26,    20,     0,    27,    32,     0,
+       0,     0,     0,    31,    30,    29,    18,    28,    33,    34,
+      19,     0,    22,     0,     0,     0,    21
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
-      -1,     3,    14,     4,     5,     6,    27,    11,    18,    25,
-      29,    44,    45,    56,    64,    65,    57,    30,    31,     7
+      -1,     2,     7,     8,    10,    13,    17,    21,    26,    37,
+      38,    50,    57,    51,    27,    28
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -14
+#define YYPACT_NINF -12
 static const yytype_int8 yypact[] =
 {
-      30,   -11,   -14,     7,   -14,    -1,    27,    13,    27,   -14,
-       8,   -14,   -14,    40,    -1,    27,    35,   -14,   -14,   -14,
-     -14,    21,   -14,   -14,    40,    24,    40,    28,    40,   -14,
-      32,    24,    46,    38,   -14,    39,   -14,   -14,    26,   -14,
-     -14,   -14,   -14,   -14,    -9,    10,   -14,   -14,   -14,   -14,
-     -14,   -14,    31,   -14,   -14,    44,    -2,     3,    23,   -14,
-     -14,   -14,   -14,   -14,    50,   -14,   -14,   -14,   -14,    40,
-     -14,   -14,    33,    40,    36,   -14
+      10,   -11,    18,    -1,   -12,    22,    -1,    15,    -1,   -12,
+      22,   -12,    20,     1,   -12,    17,   -12,   -12,    20,    20,
+     -12,     6,   -12,   -12,    21,     6,   -12,    23,     6,   -12,
+     -12,   -12,   -12,   -12,    28,   -12,   -12,    -6,    13,   -12,
+     -12,   -12,   -12,   -12,   -12,   -12,    24,   -12,   -12,    33,
+      -5,     0,    -4,   -12,   -12,   -12,   -12,   -12,   -12,   -12,
+     -12,    22,   -12,    25,    22,    19,   -12
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -14,   -14,    48,    29,    53,   -14,   -13,    47,    34,   -14,
-      37,   -14,   -14,   -14,   -14,   -14,   -14,    42,   -14,    -7
+     -12,   -12,    36,    39,   -10,   -12,     8,   -12,    12,   -12,
+     -12,   -12,   -12,   -12,    27,    31
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
    number is the opposite.  If zero, do what YYDEFACT says.
    If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -45
-static const yytype_int8 yytable[] =
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
 {
-      21,    16,    46,     8,    59,    47,    60,     9,    16,    61,
-      62,    28,    66,    33,    67,    10,    48,    13,    32,    63,
-      49,    50,    51,    52,    32,    17,    68,    19,    20,   -44,
-      53,   -44,    54,     1,   -44,     2,    26,    15,     2,    24,
-      41,     2,    34,    17,    15,    42,    19,    20,    69,    70,
-      35,    38,    39,    40,    58,    55,    72,    71,    73,    12,
-      74,    22,    75,    23,     0,     0,     0,     0,    36,     0,
-       0,     0,    43,    37
+      15,    53,     3,     5,    40,    54,    55,    41,    58,     6,
+      59,    24,    18,     1,    56,    19,    25,    42,     4,    61,
+      62,    60,    43,    44,    45,    46,    22,    23,     9,    12,
+      20,    47,    31,    48,    29,    16,    16,    32,    30,    34,
+      35,    39,    52,    66,    14,    11,    49,     0,    64,     0,
+       0,    63,     0,     0,    65,    36,    33
 };
 
 static const yytype_int8 yycheck[] =
 {
-      13,     8,    11,    14,     6,    14,     8,     0,    15,    11,
-      12,    24,     9,    26,    11,    16,    25,     4,    25,    21,
-      10,    11,    12,    13,    31,    17,    23,     6,     7,     5,
-      20,     4,    22,     3,     4,    11,    15,     8,    11,     4,
-      14,    11,    14,    17,    15,    19,     6,     7,    25,    26,
-      18,     5,    14,    14,    10,    24,    69,     7,    25,     6,
-      73,    14,    26,    15,    -1,    -1,    -1,    -1,    31,    -1,
-      -1,    -1,    38,    31
+      10,     6,    13,     4,    10,    10,    11,    13,     8,    10,
+      10,     5,    11,     3,    19,    14,    10,    23,     0,    23,
+      24,    21,     9,    10,    11,    12,    18,    19,     6,    14,
+      13,    18,    24,    20,    13,    15,    15,    25,    17,    16,
+      28,    13,     9,    24,     8,     6,    22,    -1,    23,    -1,
+      -1,    61,    -1,    -1,    64,    28,    25
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,     3,    11,    28,    30,    31,    32,    46,    14,     0,
-      16,    34,    31,     4,    29,    30,    46,    17,    35,     6,
-       7,    33,    34,    29,     4,    36,    15,    33,    33,    37,
-      44,    45,    46,    33,    14,    18,    37,    44,     5,    14,
-      14,    14,    19,    35,    38,    39,    11,    14,    25,    10,
-      11,    12,    13,    20,    22,    24,    40,    43,    10,     6,
-       8,    11,    12,    21,    41,    42,     9,    11,    23,    25,
-      26,     7,    33,    25,    33,    26
+       0,     3,    26,    13,     0,     4,    10,    27,    28,     6,
+      29,    28,    14,    30,    27,    29,    15,    31,    11,    14,
+      13,    32,    31,    31,     5,    10,    33,    39,    40,    13,
+      17,    31,    33,    40,    16,    33,    39,    34,    35,    13,
+      10,    13,    23,     9,    10,    11,    12,    18,    20,    22,
+      36,    38,     9,     6,    10,    11,    19,    37,     8,    10,
+      21,    23,    24,    29,    23,    29,    24
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -728,7 +705,7 @@ do {                                                                          \
     {                                                                    \
       YYFPRINTF (stderr, "%s ", Title);                                          \
       yy_symbol_print (stderr,                                           \
-                 Type, Value, Location); \
+                 Type, Value); \
       YYFPRINTF (stderr, "\n");                                                  \
     }                                                                    \
 } while (YYID (0))
@@ -742,19 +719,17 @@ do {                                                                        \
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp)
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
 #else
 static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp)
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
     FILE *yyoutput;
     int yytype;
     YYSTYPE const * const yyvaluep;
-    YYLTYPE const * const yylocationp;
 #endif
 {
   if (!yyvaluep)
     return;
-  YYUSE (yylocationp);
 # ifdef YYPRINT
   if (yytype < YYNTOKENS)
     YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
@@ -776,14 +751,13 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp)
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
 #else
 static void
-yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp)
+yy_symbol_print (yyoutput, yytype, yyvaluep)
     FILE *yyoutput;
     int yytype;
     YYSTYPE const * const yyvaluep;
-    YYLTYPE const * const yylocationp;
 #endif
 {
   if (yytype < YYNTOKENS)
@@ -791,9 +765,7 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp)
   else
     YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
 
-  YY_LOCATION_PRINT (yyoutput, *yylocationp);
-  YYFPRINTF (yyoutput, ": ");
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp);
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
   YYFPRINTF (yyoutput, ")");
 }
 
@@ -805,17 +777,20 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
 #else
 static void
-yy_stack_print (bottom, top)
-    yytype_int16 *bottom;
-    yytype_int16 *top;
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
 #endif
 {
   YYFPRINTF (stderr, "Stack now");
-  for (; bottom <= top; ++bottom)
-    YYFPRINTF (stderr, " %d", *bottom);
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
   YYFPRINTF (stderr, "\n");
 }
 
@@ -833,12 +808,11 @@ do {                                                              \
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule)
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
 #else
 static void
-yy_reduce_print (yyvsp, yylsp, yyrule)
+yy_reduce_print (yyvsp, yyrule)
     YYSTYPE *yyvsp;
-    YYLTYPE *yylsp;
     int yyrule;
 #endif
 {
@@ -850,18 +824,18 @@ yy_reduce_print (yyvsp, yylsp, yyrule)
   /* The symbols being reduced.  */
   for (yyi = 0; yyi < yynrhs; yyi++)
     {
-      fprintf (stderr, "   $%d = ", yyi + 1);
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
       yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
                       &(yyvsp[(yyi + 1) - (yynrhs)])
-                      , &(yylsp[(yyi + 1) - (yynrhs)])                );
-      fprintf (stderr, "\n");
+                                      );
+      YYFPRINTF (stderr, "\n");
     }
 }
 
 # define YY_REDUCE_PRINT(Rule)         \
 do {                                   \
   if (yydebug)                         \
-    yy_reduce_print (yyvsp, yylsp, Rule); \
+    yy_reduce_print (yyvsp, Rule); \
 } while (YYID (0))
 
 /* Nonzero means print parse trace.  It is left uninitialized so that
@@ -1112,18 +1086,16 @@ yysyntax_error (char *yyresult, int yystate, int yychar)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
 #else
 static void
-yydestruct (yymsg, yytype, yyvaluep, yylocationp)
+yydestruct (yymsg, yytype, yyvaluep)
     const char *yymsg;
     int yytype;
     YYSTYPE *yyvaluep;
-    YYLTYPE *yylocationp;
 #endif
 {
   YYUSE (yyvaluep);
-  YYUSE (yylocationp);
 
   if (!yymsg)
     yymsg = "Deleting";
@@ -1136,10 +1108,8 @@ yydestruct (yymsg, yytype, yyvaluep, yylocationp)
        break;
     }
 }
-\f
 
 /* Prevent warnings from -Wmissing-prototypes.  */
-
 #ifdef YYPARSE_PARAM
 #if defined __STDC__ || defined __cplusplus
 int yyparse (void *YYPARSE_PARAM);
@@ -1155,23 +1125,20 @@ int yyparse ();
 #endif /* ! YYPARSE_PARAM */
 
 
-
-/* The look-ahead symbol.  */
+/* The lookahead symbol.  */
 int yychar;
 
-/* The semantic value of the look-ahead symbol.  */
+/* The semantic value of the lookahead symbol.  */
 YYSTYPE yylval;
 
 /* Number of syntax errors so far.  */
 int yynerrs;
-/* Location data for the look-ahead symbol.  */
-YYLTYPE yylloc;
 
 
 
-/*----------.
-| yyparse.  |
-`----------*/
+/*-------------------------.
+| yyparse or yypush_parse.  |
+`-------------------------*/
 
 #ifdef YYPARSE_PARAM
 #if (defined __STDC__ || defined __C99__FUNC__ \
@@ -1195,79 +1162,70 @@ yyparse ()
 #endif
 #endif
 {
-  
-  int yystate;
-  int yyn;
-  int yyresult;
-  /* Number of tokens to shift before error messages enabled.  */
-  int yyerrstatus;
-  /* Look-ahead token as an internal (translated) token number.  */
-  int yytoken = 0;
-#if YYERROR_VERBOSE
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
 
-  /* Three stacks and their tools:
-     `yyss': related to states,
-     `yyvs': related to semantic values,
-     `yyls': related to locations.
 
-     Refer to the stacks thru separate pointers, to allow yyoverflow
-     to reallocate them elsewhere.  */
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
 
-  /* The state stack.  */
-  yytype_int16 yyssa[YYINITDEPTH];
-  yytype_int16 *yyss = yyssa;
-  yytype_int16 *yyssp;
+    /* The stacks and their tools:
+       `yyss': related to states.
+       `yyvs': related to semantic values.
 
-  /* The semantic value stack.  */
-  YYSTYPE yyvsa[YYINITDEPTH];
-  YYSTYPE *yyvs = yyvsa;
-  YYSTYPE *yyvsp;
+       Refer to the stacks thru separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
 
-  /* The location stack.  */
-  YYLTYPE yylsa[YYINITDEPTH];
-  YYLTYPE *yyls = yylsa;
-  YYLTYPE *yylsp;
-  /* The locations where the error started and ended.  */
-  YYLTYPE yyerror_range[2];
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
 
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
 
-  YYSIZE_T yystacksize = YYINITDEPTH;
+    YYSIZE_T yystacksize;
 
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE yyval;
-  YYLTYPE yyloc;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
 
   /* The number of symbols on the RHS of the reduced rule.
      Keep to zero when no symbol should be popped.  */
   int yylen = 0;
 
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
   YYDPRINTF ((stderr, "Starting parse\n"));
 
   yystate = 0;
   yyerrstatus = 0;
   yynerrs = 0;
-  yychar = YYEMPTY;            /* Cause a token to be read.  */
+  yychar = YYEMPTY; /* Cause a token to be read.  */
 
   /* Initialize stack pointers.
      Waste one element of value and location stack
      so that they stay on the same level as the state stack.
      The wasted elements are never initialized.  */
-
   yyssp = yyss;
   yyvsp = yyvs;
-  yylsp = yyls;
-#if YYLTYPE_IS_TRIVIAL
-  /* Initialize the default location before parsing starts.  */
-  yylloc.first_line   = yylloc.last_line   = 1;
-  yylloc.first_column = yylloc.last_column = 0;
-#endif
 
   goto yysetstate;
 
@@ -1294,7 +1252,6 @@ yyparse ()
           memory.  */
        YYSTYPE *yyvs1 = yyvs;
        yytype_int16 *yyss1 = yyss;
-       YYLTYPE *yyls1 = yyls;
 
        /* Each stack pointer address is followed by the size of the
           data in use in that stack, in bytes.  This used to be a
@@ -1303,9 +1260,8 @@ yyparse ()
        yyoverflow (YY_("memory exhausted"),
                    &yyss1, yysize * sizeof (*yyssp),
                    &yyvs1, yysize * sizeof (*yyvsp),
-                   &yyls1, yysize * sizeof (*yylsp),
                    &yystacksize);
-       yyls = yyls1;
+
        yyss = yyss1;
        yyvs = yyvs1;
       }
@@ -1326,9 +1282,8 @@ yyparse ()
          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
        if (! yyptr)
          goto yyexhaustedlab;
-       YYSTACK_RELOCATE (yyss);
-       YYSTACK_RELOCATE (yyvs);
-       YYSTACK_RELOCATE (yyls);
+       YYSTACK_RELOCATE (yyss_alloc, yyss);
+       YYSTACK_RELOCATE (yyvs_alloc, yyvs);
 #  undef YYSTACK_RELOCATE
        if (yyss1 != yyssa)
          YYSTACK_FREE (yyss1);
@@ -1338,7 +1293,6 @@ yyparse ()
 
       yyssp = yyss + yysize - 1;
       yyvsp = yyvs + yysize - 1;
-      yylsp = yyls + yysize - 1;
 
       YYDPRINTF ((stderr, "Stack size increased to %lu\n",
                  (unsigned long int) yystacksize));
@@ -1349,6 +1303,9 @@ yyparse ()
 
   YYDPRINTF ((stderr, "Entering state %d\n", yystate));
 
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
   goto yybackup;
 
 /*-----------.
@@ -1357,16 +1314,16 @@ yyparse ()
 yybackup:
 
   /* Do appropriate processing given the current state.  Read a
-     look-ahead token if we need one and don't already have one.  */
+     lookahead token if we need one and don't already have one.  */
 
-  /* First try to decide what to do without reference to look-ahead token.  */
+  /* First try to decide what to do without reference to lookahead token.  */
   yyn = yypact[yystate];
   if (yyn == YYPACT_NINF)
     goto yydefault;
 
-  /* Not known => get a look-ahead token if don't already have one.  */
+  /* Not known => get a lookahead token if don't already have one.  */
 
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
   if (yychar == YYEMPTY)
     {
       YYDPRINTF ((stderr, "Reading a token: "));
@@ -1398,24 +1355,20 @@ yybackup:
       goto yyreduce;
     }
 
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
   /* Count tokens shifted since error; after three, turn off error
      status.  */
   if (yyerrstatus)
     yyerrstatus--;
 
-  /* Shift the look-ahead token.  */
+  /* Shift the lookahead token.  */
   YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
 
-  /* Discard the shifted token unless it is eof.  */
-  if (yychar != YYEOF)
-    yychar = YYEMPTY;
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
 
   yystate = yyn;
   *++yyvsp = yylval;
-  *++yylsp = yylloc;
+
   goto yynewstate;
 
 
@@ -1446,337 +1399,387 @@ yyreduce:
      GCC warning that YYVAL may be used uninitialized.  */
   yyval = yyvsp[1-yylen];
 
-  /* Default location.  */
-  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
         case 2:
-#line 90 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 87 "dtc-parser.y"
     {
-                       the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node), 0);
+                       the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node),
+                                                       guess_boot_cpuid((yyvsp[(4) - (4)].node)));
                ;}
     break;
 
   case 3:
-#line 94 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 95 "dtc-parser.y"
     {
-                       the_boot_info = build_boot_info((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].node), 0);
+                       (yyval.re) = NULL;
                ;}
     break;
 
   case 4:
-#line 101 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 99 "dtc-parser.y"
     {
-                       (yyval.re) = NULL;
+                       (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
                ;}
     break;
 
   case 5:
-#line 105 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 106 "dtc-parser.y"
     {
-                       (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
+                       (yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].addr), (yyvsp[(3) - (4)].addr));
                ;}
     break;
 
   case 6:
-#line 112 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 110 "dtc-parser.y"
     {
-                       (yyval.re) = build_reserve_entry((yyvsp[(3) - (5)].addr), (yyvsp[(4) - (5)].addr), (yyvsp[(1) - (5)].labelref));
+                       add_label(&(yyvsp[(2) - (2)].re)->labels, (yyvsp[(1) - (2)].labelref));
+                       (yyval.re) = (yyvsp[(2) - (2)].re);
                ;}
     break;
 
   case 7:
-#line 119 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 118 "dtc-parser.y"
     {
-                       (yyval.re) = NULL;
+                       (yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64);
                ;}
     break;
 
   case 8:
-#line 123 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 125 "dtc-parser.y"
     {
-                       (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
+                       (yyval.node) = name_node((yyvsp[(2) - (2)].node), "");
                ;}
     break;
 
   case 9:
-#line 130 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 129 "dtc-parser.y"
     {
-                       (yyval.re) = (yyvsp[(1) - (1)].re);
+                       (yyval.node) = merge_nodes((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
                ;}
     break;
 
   case 10:
-#line 134 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 133 "dtc-parser.y"
     {
-                       (yyval.re) = build_reserve_entry((yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr) - (yyvsp[(3) - (6)].addr) + 1, (yyvsp[(1) - (6)].labelref));
+                       struct node *target = get_node_by_ref((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].labelref));
+
+                       if (target)
+                               merge_nodes(target, (yyvsp[(3) - (3)].node));
+                       else
+                               print_error("label or path, '%s', not found", (yyvsp[(2) - (3)].labelref));
+                       (yyval.node) = (yyvsp[(1) - (3)].node);
                ;}
     break;
 
   case 11:
-#line 141 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 146 "dtc-parser.y"
     {
-                       (yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64);
+                       (yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist));
                ;}
     break;
 
   case 12:
-#line 145 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 153 "dtc-parser.y"
     {
-                       (yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 16, 64);
+                       (yyval.proplist) = NULL;
                ;}
     break;
 
   case 13:
-#line 152 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 157 "dtc-parser.y"
     {
-                       (yyval.node) = name_node((yyvsp[(2) - (2)].node), "", NULL);
+                       (yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist));
                ;}
     break;
 
   case 14:
-#line 159 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 164 "dtc-parser.y"
     {
-                       (yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist));
+                       (yyval.prop) = build_property((yyvsp[(1) - (4)].propnodename), (yyvsp[(3) - (4)].data));
                ;}
     break;
 
   case 15:
-#line 166 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 168 "dtc-parser.y"
     {
-                       (yyval.proplist) = NULL;
+                       (yyval.prop) = build_property((yyvsp[(1) - (2)].propnodename), empty_data);
                ;}
     break;
 
   case 16:
-#line 170 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 172 "dtc-parser.y"
     {
-                       (yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist));
+                       add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref));
+                       (yyval.prop) = (yyvsp[(2) - (2)].prop);
                ;}
     break;
 
   case 17:
-#line 177 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 180 "dtc-parser.y"
     {
-                       (yyval.prop) = build_property((yyvsp[(2) - (5)].propnodename), (yyvsp[(4) - (5)].data), (yyvsp[(1) - (5)].labelref));
+                       (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data));
                ;}
     break;
 
   case 18:
-#line 181 "dtc-parser.y"
+
+/* Line 1455 of yacc.c  */
+#line 184 "dtc-parser.y"
     {
-                       (yyval.prop) = build_property((yyvsp[(2) - (3)].propnodename), empty_data, (yyvsp[(1) - (3)].labelref));
+                       (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
                ;}
     break;
 
   case 19:
+
+/* Line 1455 of yacc.c  */
 #line 188 "dtc-parser.y"
     {
-                       (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data));
+                       (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
                ;}
     break;
 
   case 20:
+
+/* Line 1455 of yacc.c  */
 #line 192 "dtc-parser.y"
     {
-                       (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
+                       (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref));
                ;}
     break;
 
   case 21:
-#line 196 "dtc-parser.y"
-    {
-                       (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
-               ;}
-    break;
-
-  case 22:
-#line 200 "dtc-parser.y"
-    {
-                       (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref));
-               ;}
-    break;
 
-  case 23:
-#line 204 "dtc-parser.y"
+/* Line 1455 of yacc.c  */
+#line 196 "dtc-parser.y"
     {
-                       struct search_path path = { srcpos_file->dir, NULL, NULL };
-                       struct dtc_file *file = dtc_open_file((yyvsp[(4) - (9)].data).val, &path);
-                       struct data d = empty_data;
+                       FILE *f = srcfile_relative_open((yyvsp[(4) - (9)].data).val, NULL);
+                       struct data d;
 
                        if ((yyvsp[(6) - (9)].addr) != 0)
-                               if (fseek(file->file, (yyvsp[(6) - (9)].addr), SEEK_SET) != 0)
-                                       yyerrorf("Couldn't seek to offset %llu in \"%s\": %s",
-                                                (unsigned long long)(yyvsp[(6) - (9)].addr),
-                                                (yyvsp[(4) - (9)].data).val, strerror(errno));
+                               if (fseek(f, (yyvsp[(6) - (9)].addr), SEEK_SET) != 0)
+                                       print_error("Couldn't seek to offset %llu in \"%s\": %s",
+                                                    (unsigned long long)(yyvsp[(6) - (9)].addr),
+                                                    (yyvsp[(4) - (9)].data).val,
+                                                    strerror(errno));
 
-                       d = data_copy_file(file->file, (yyvsp[(8) - (9)].addr));
+                       d = data_copy_file(f, (yyvsp[(8) - (9)].addr));
 
                        (yyval.data) = data_merge((yyvsp[(1) - (9)].data), d);
-                       dtc_close_file(file);
+                       fclose(f);
                ;}
     break;
 
-  case 24:
-#line 221 "dtc-parser.y"
+  case 22:
+
+/* Line 1455 of yacc.c  */
+#line 213 "dtc-parser.y"
     {
-                       struct search_path path = { srcpos_file->dir, NULL, NULL };
-                       struct dtc_file *file = dtc_open_file((yyvsp[(4) - (5)].data).val, &path);
+                       FILE *f = srcfile_relative_open((yyvsp[(4) - (5)].data).val, NULL);
                        struct data d = empty_data;
 
-                       d = data_copy_file(file->file, -1);
+                       d = data_copy_file(f, -1);
 
                        (yyval.data) = data_merge((yyvsp[(1) - (5)].data), d);
-                       dtc_close_file(file);
+                       fclose(f);
                ;}
     break;
 
-  case 25:
-#line 232 "dtc-parser.y"
+  case 23:
+
+/* Line 1455 of yacc.c  */
+#line 223 "dtc-parser.y"
     {
                        (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
                ;}
     break;
 
-  case 26:
-#line 239 "dtc-parser.y"
+  case 24:
+
+/* Line 1455 of yacc.c  */
+#line 230 "dtc-parser.y"
     {
                        (yyval.data) = empty_data;
                ;}
     break;
 
-  case 27:
-#line 243 "dtc-parser.y"
+  case 25:
+
+/* Line 1455 of yacc.c  */
+#line 234 "dtc-parser.y"
     {
                        (yyval.data) = (yyvsp[(1) - (2)].data);
                ;}
     break;
 
-  case 28:
-#line 247 "dtc-parser.y"
+  case 26:
+
+/* Line 1455 of yacc.c  */
+#line 238 "dtc-parser.y"
     {
                        (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
                ;}
     break;
 
-  case 29:
-#line 254 "dtc-parser.y"
+  case 27:
+
+/* Line 1455 of yacc.c  */
+#line 245 "dtc-parser.y"
     {
                        (yyval.data) = empty_data;
                ;}
     break;
 
-  case 30:
-#line 258 "dtc-parser.y"
+  case 28:
+
+/* Line 1455 of yacc.c  */
+#line 249 "dtc-parser.y"
     {
                        (yyval.data) = data_append_cell((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].cell));
                ;}
     break;
 
-  case 31:
-#line 262 "dtc-parser.y"
+  case 29:
+
+/* Line 1455 of yacc.c  */
+#line 253 "dtc-parser.y"
     {
                        (yyval.data) = data_append_cell(data_add_marker((yyvsp[(1) - (2)].data), REF_PHANDLE,
                                                              (yyvsp[(2) - (2)].labelref)), -1);
                ;}
     break;
 
-  case 32:
-#line 267 "dtc-parser.y"
+  case 30:
+
+/* Line 1455 of yacc.c  */
+#line 258 "dtc-parser.y"
     {
                        (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
                ;}
     break;
 
-  case 33:
-#line 274 "dtc-parser.y"
-    {
-                       (yyval.cbase) = 16;
-               ;}
-    break;
+  case 31:
 
-  case 35:
-#line 282 "dtc-parser.y"
+/* Line 1455 of yacc.c  */
+#line 265 "dtc-parser.y"
     {
                        (yyval.cell) = eval_literal((yyvsp[(1) - (1)].literal), 0, 32);
                ;}
     break;
 
-  case 36:
-#line 286 "dtc-parser.y"
-    {
-                       (yyval.cell) = eval_literal((yyvsp[(2) - (2)].literal), (yyvsp[(1) - (2)].cbase), 32);
-               ;}
-    break;
+  case 32:
 
-  case 37:
-#line 293 "dtc-parser.y"
+/* Line 1455 of yacc.c  */
+#line 272 "dtc-parser.y"
     {
                        (yyval.data) = empty_data;
                ;}
     break;
 
-  case 38:
-#line 297 "dtc-parser.y"
+  case 33:
+
+/* Line 1455 of yacc.c  */
+#line 276 "dtc-parser.y"
     {
                        (yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte));
                ;}
     break;
 
-  case 39:
-#line 301 "dtc-parser.y"
+  case 34:
+
+/* Line 1455 of yacc.c  */
+#line 280 "dtc-parser.y"
     {
                        (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
                ;}
     break;
 
-  case 40:
-#line 308 "dtc-parser.y"
+  case 35:
+
+/* Line 1455 of yacc.c  */
+#line 287 "dtc-parser.y"
     {
                        (yyval.nodelist) = NULL;
                ;}
     break;
 
-  case 41:
-#line 312 "dtc-parser.y"
+  case 36:
+
+/* Line 1455 of yacc.c  */
+#line 291 "dtc-parser.y"
     {
                        (yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist));
                ;}
     break;
 
-  case 42:
-#line 316 "dtc-parser.y"
+  case 37:
+
+/* Line 1455 of yacc.c  */
+#line 295 "dtc-parser.y"
     {
-                       yyerror("syntax error: properties must precede subnodes");
+                       print_error("syntax error: properties must precede subnodes");
                        YYERROR;
                ;}
     break;
 
-  case 43:
-#line 324 "dtc-parser.y"
-    {
-                       (yyval.node) = name_node((yyvsp[(3) - (3)].node), (yyvsp[(2) - (3)].propnodename), (yyvsp[(1) - (3)].labelref));
-               ;}
-    break;
+  case 38:
 
-  case 44:
-#line 331 "dtc-parser.y"
+/* Line 1455 of yacc.c  */
+#line 303 "dtc-parser.y"
     {
-                       (yyval.labelref) = NULL;
+                       (yyval.node) = name_node((yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].propnodename));
                ;}
     break;
 
-  case 45:
-#line 335 "dtc-parser.y"
+  case 39:
+
+/* Line 1455 of yacc.c  */
+#line 307 "dtc-parser.y"
     {
-                       (yyval.labelref) = (yyvsp[(1) - (1)].labelref);
+                       add_label(&(yyvsp[(2) - (2)].node)->labels, (yyvsp[(1) - (2)].labelref));
+                       (yyval.node) = (yyvsp[(2) - (2)].node);
                ;}
     break;
 
 
-/* Line 1267 of yacc.c.  */
-#line 1780 "dtc-parser.tab.c"
+
+/* Line 1455 of yacc.c  */
+#line 1783 "dtc-parser.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -1786,7 +1789,6 @@ yyreduce:
   YY_STACK_PRINT (yyss, yyssp);
 
   *++yyvsp = yyval;
-  *++yylsp = yyloc;
 
   /* Now `shift' the result of the reduction.  Determine what state
      that goes to, based on the state we popped back to and the rule
@@ -1848,11 +1850,11 @@ yyerrlab:
 #endif
     }
 
-  yyerror_range[0] = yylloc;
+
 
   if (yyerrstatus == 3)
     {
-      /* If just tried and failed to reuse look-ahead token after an
+      /* If just tried and failed to reuse lookahead token after an
         error, discard it.  */
 
       if (yychar <= YYEOF)
@@ -1864,12 +1866,12 @@ yyerrlab:
       else
        {
          yydestruct ("Error: discarding",
-                     yytoken, &yylval, &yylloc);
+                     yytoken, &yylval);
          yychar = YYEMPTY;
        }
     }
 
-  /* Else will try to reuse look-ahead token after shifting the error
+  /* Else will try to reuse lookahead token after shifting the error
      token.  */
   goto yyerrlab1;
 
@@ -1885,7 +1887,6 @@ yyerrorlab:
   if (/*CONSTCOND*/ 0)
      goto yyerrorlab;
 
-  yyerror_range[0] = yylsp[1-yylen];
   /* Do not reclaim the symbols of the rule which action triggered
      this YYERROR.  */
   YYPOPSTACK (yylen);
@@ -1919,24 +1920,16 @@ yyerrlab1:
       if (yyssp == yyss)
        YYABORT;
 
-      yyerror_range[0] = *yylsp;
+
       yydestruct ("Error: popping",
-                 yystos[yystate], yyvsp, yylsp);
+                 yystos[yystate], yyvsp);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
     }
 
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
   *++yyvsp = yylval;
 
-  yyerror_range[1] = yylloc;
-  /* Using YYLLOC is tempting, but would change the location of
-     the look-ahead.  YYLOC is available though.  */
-  YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
-  *++yylsp = yyloc;
 
   /* Shift the error token.  */
   YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
@@ -1959,7 +1952,7 @@ yyabortlab:
   yyresult = 1;
   goto yyreturn;
 
-#ifndef yyoverflow
+#if !defined(yyoverflow) || YYERROR_VERBOSE
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
@@ -1970,9 +1963,9 @@ yyexhaustedlab:
 #endif
 
 yyreturn:
-  if (yychar != YYEOF && yychar != YYEMPTY)
+  if (yychar != YYEMPTY)
      yydestruct ("Cleanup: discarding lookahead",
-                yytoken, &yylval, &yylloc);
+                yytoken, &yylval);
   /* Do not reclaim the symbols of the rule which action triggered
      this YYABORT or YYACCEPT.  */
   YYPOPSTACK (yylen);
@@ -1980,7 +1973,7 @@ yyreturn:
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-                 yystos[*yyssp], yyvsp, yylsp);
+                 yystos[*yyssp], yyvsp);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
@@ -1996,29 +1989,24 @@ yyreturn:
 }
 
 
-#line 340 "dtc-parser.y"
+
+/* Line 1675 of yacc.c  */
+#line 313 "dtc-parser.y"
 
 
-void yyerrorf(char const *s, ...)
+void print_error(char const *fmt, ...)
 {
-       const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
        va_list va;
-       va_start(va, s);
-
-       if (strcmp(fname, "-") == 0)
-               fname = "stdin";
 
-       fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
-       vfprintf(stderr, s, va);
-       fprintf(stderr, "\n");
+       va_start(va, fmt);
+       srcpos_verror(&yylloc, fmt, va);
+       va_end(va);
 
        treesource_error = 1;
-       va_end(va);
 }
 
-void yyerror (char const *s)
-{
-       yyerrorf("%s", s);
+void yyerror(char const *s) {
+       print_error("%s", s);
 }
 
 static unsigned long long eval_literal(const char *s, int base, int bits)
@@ -2029,12 +2017,12 @@ static unsigned long long eval_literal(const char *s, int base, int bits)
        errno = 0;
        val = strtoull(s, &e, base);
        if (*e)
-               yyerror("bad characters in literal");
+               print_error("bad characters in literal");
        else if ((errno == ERANGE)
                 || ((bits < 64) && (val >= (1ULL << bits))))
-               yyerror("literal out of range");
+               print_error("literal out of range");
        else if (errno != 0)
-               yyerror("bad literal");
+               print_error("bad literal");
        return val;
 }
 
index ba99100d55c980e4281976df0ebbe4de31bdc541..95c9547adea52881532599186551d28e8791b587 100644 (file)
@@ -1,24 +1,23 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
 
-/* Skeleton interface for Bison's Yacc-like parsers in C
+/* A Bison parser, made by GNU Bison 2.4.1.  */
 
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+/* Skeleton interface for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
+   
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-
+   
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-
+   
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
+
 /* Tokens.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
      DT_MEMRESERVE = 259,
      DT_PROPNODENAME = 260,
      DT_LITERAL = 261,
-     DT_LEGACYLITERAL = 262,
-     DT_BASE = 263,
-     DT_BYTE = 264,
-     DT_STRING = 265,
-     DT_LABEL = 266,
-     DT_REF = 267,
-     DT_INCBIN = 268
+     DT_BASE = 262,
+     DT_BYTE = 263,
+     DT_STRING = 264,
+     DT_LABEL = 265,
+     DT_REF = 266,
+     DT_INCBIN = 267
    };
 #endif
-/* Tokens.  */
-#define DT_V1 258
-#define DT_MEMRESERVE 259
-#define DT_PROPNODENAME 260
-#define DT_LITERAL 261
-#define DT_LEGACYLITERAL 262
-#define DT_BASE 263
-#define DT_BYTE 264
-#define DT_STRING 265
-#define DT_LABEL 266
-#define DT_REF 267
-#define DT_INCBIN 268
-
 
 
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 37 "dtc-parser.y"
 {
+
+/* Line 1676 of yacc.c  */
+#line 39 "dtc-parser.y"
+
        char *propnodename;
        char *literal;
        char *labelref;
@@ -86,28 +75,17 @@ typedef union YYSTYPE
        struct node *node;
        struct node *nodelist;
        struct reserve_info *re;
-}
-/* Line 1489 of yacc.c.  */
-#line 92 "dtc-parser.tab.h"
-       YYSTYPE;
+
+
+
+/* Line 1676 of yacc.c  */
+#line 83 "dtc-parser.tab.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
 #endif
 
 extern YYSTYPE yylval;
 
-#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
-typedef struct YYLTYPE
-{
-  int first_line;
-  int first_column;
-  int last_line;
-  int last_column;
-} YYLTYPE;
-# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
-# define YYLTYPE_IS_DECLARED 1
-# define YYLTYPE_IS_TRIVIAL 1
-#endif
 
-extern YYLTYPE yylloc;
index b2ab562420ead9815ac83adf4372bece16e10f23..5e84a67fc1d2bf110d0d33040d9d3178f5bbddb6 100644 (file)
  *                                                                   USA
  */
 
-%locations
-
 %{
 #include <stdio.h>
 
 #include "dtc.h"
 #include "srcpos.h"
 
+YYLTYPE yylloc;
+
 extern int yylex(void);
+extern void print_error(char const *fmt, ...);
+extern void yyerror(char const *s);
 
 extern struct boot_info *the_boot_info;
 extern int treesource_error;
@@ -55,7 +57,6 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
 %token DT_MEMRESERVE
 %token <propnodename> DT_PROPNODENAME
 %token <literal> DT_LITERAL
-%token <literal> DT_LEGACYLITERAL
 %token <cbase> DT_BASE
 %token <byte> DT_BYTE
 %token <data> DT_STRING
@@ -67,11 +68,8 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
 %type <data> propdataprefix
 %type <re> memreserve
 %type <re> memreserves
-%type <re> v0_memreserve
-%type <re> v0_memreserves
 %type <addr> addr
 %type <data> celllist
-%type <cbase> cellbase
 %type <cell> cellval
 %type <data> bytestring
 %type <prop> propdef
@@ -81,18 +79,14 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
 %type <node> nodedef
 %type <node> subnode
 %type <nodelist> subnodes
-%type <labelref> label
 
 %%
 
 sourcefile:
          DT_V1 ';' memreserves devicetree
                {
-                       the_boot_info = build_boot_info($3, $4, 0);
-               }
-       | v0_memreserves devicetree
-               {
-                       the_boot_info = build_boot_info($1, $2, 0);
+                       the_boot_info = build_boot_info($3, $4,
+                                                       guess_boot_cpuid($4));
                }
        ;
 
@@ -108,31 +102,14 @@ memreserves:
        ;
 
 memreserve:
-         label DT_MEMRESERVE addr addr ';'
+         DT_MEMRESERVE addr addr ';'
                {
-                       $$ = build_reserve_entry($3, $4, $1);
+                       $$ = build_reserve_entry($2, $3);
                }
-       ;
-
-v0_memreserves:
-         /* empty */
+       | DT_LABEL memreserve
                {
-                       $$ = NULL;
-               }
-       | v0_memreserve v0_memreserves
-               {
-                       $$ = chain_reserve_entry($1, $2);
-               };
-       ;
-
-v0_memreserve:
-         memreserve
-               {
-                       $$ = $1;
-               }
-       | label DT_MEMRESERVE addr '-' addr ';'
-               {
-                       $$ = build_reserve_entry($3, $5 - $3 + 1, $1);
+                       add_label(&$2->labels, $1);
+                       $$ = $2;
                }
        ;
 
@@ -141,16 +118,26 @@ addr:
                {
                        $$ = eval_literal($1, 0, 64);
                }
-       | DT_LEGACYLITERAL
-               {
-                       $$ = eval_literal($1, 16, 64);
-               }
          ;
 
 devicetree:
          '/' nodedef
                {
-                       $$ = name_node($2, "", NULL);
+                       $$ = name_node($2, "");
+               }
+       | devicetree '/' nodedef
+               {
+                       $$ = merge_nodes($1, $3);
+               }
+       | devicetree DT_REF nodedef
+               {
+                       struct node *target = get_node_by_ref($1, $2);
+
+                       if (target)
+                               merge_nodes(target, $3);
+                       else
+                               print_error("label or path, '%s', not found", $2);
+                       $$ = $1;
                }
        ;
 
@@ -173,13 +160,18 @@ proplist:
        ;
 
 propdef:
-         label DT_PROPNODENAME '=' propdata ';'
+         DT_PROPNODENAME '=' propdata ';'
+               {
+                       $$ = build_property($1, $3);
+               }
+       | DT_PROPNODENAME ';'
                {
-                       $$ = build_property($2, $4, $1);
+                       $$ = build_property($1, empty_data);
                }
-       | label DT_PROPNODENAME ';'
+       | DT_LABEL propdef
                {
-                       $$ = build_property($2, empty_data, $1);
+                       add_label(&$2->labels, $1);
+                       $$ = $2;
                }
        ;
 
@@ -202,31 +194,30 @@ propdata:
                }
        | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
                {
-                       struct search_path path = { srcpos_file->dir, NULL, NULL };
-                       struct dtc_file *file = dtc_open_file($4.val, &path);
-                       struct data d = empty_data;
+                       FILE *f = srcfile_relative_open($4.val, NULL);
+                       struct data d;
 
                        if ($6 != 0)
-                               if (fseek(file->file, $6, SEEK_SET) != 0)
-                                       yyerrorf("Couldn't seek to offset %llu in \"%s\": %s",
-                                                (unsigned long long)$6,
-                                                $4.val, strerror(errno));
+                               if (fseek(f, $6, SEEK_SET) != 0)
+                                       print_error("Couldn't seek to offset %llu in \"%s\": %s",
+                                                    (unsigned long long)$6,
+                                                    $4.val,
+                                                    strerror(errno));
 
-                       d = data_copy_file(file->file, $8);
+                       d = data_copy_file(f, $8);
 
                        $$ = data_merge($1, d);
-                       dtc_close_file(file);
+                       fclose(f);
                }
        | propdataprefix DT_INCBIN '(' DT_STRING ')'
                {
-                       struct search_path path = { srcpos_file->dir, NULL, NULL };
-                       struct dtc_file *file = dtc_open_file($4.val, &path);
+                       FILE *f = srcfile_relative_open($4.val, NULL);
                        struct data d = empty_data;
 
-                       d = data_copy_file(file->file, -1);
+                       d = data_copy_file(f, -1);
 
                        $$ = data_merge($1, d);
-                       dtc_close_file(file);
+                       fclose(f);
                }
        | propdata DT_LABEL
                {
@@ -269,23 +260,11 @@ celllist:
                }
        ;
 
-cellbase:
-         /* empty */
-               {
-                       $$ = 16;
-               }
-       | DT_BASE
-       ;
-
 cellval:
          DT_LITERAL
                {
                        $$ = eval_literal($1, 0, 32);
                }
-       | cellbase DT_LEGACYLITERAL
-               {
-                       $$ = eval_literal($2, $1, 32);
-               }
        ;
 
 bytestring:
@@ -308,57 +287,44 @@ subnodes:
                {
                        $$ = NULL;
                }
-       |  subnode subnodes
+       | subnode subnodes
                {
                        $$ = chain_node($1, $2);
                }
        | subnode propdef
                {
-                       yyerror("syntax error: properties must precede subnodes");
+                       print_error("syntax error: properties must precede subnodes");
                        YYERROR;
                }
        ;
 
 subnode:
-         label DT_PROPNODENAME nodedef
+         DT_PROPNODENAME nodedef
                {
-                       $$ = name_node($3, $2, $1);
+                       $$ = name_node($2, $1);
                }
-       ;
-
-label:
-         /* empty */
+       | DT_LABEL subnode
                {
-                       $$ = NULL;
-               }
-       | DT_LABEL
-               {
-                       $$ = $1;
+                       add_label(&$2->labels, $1);
+                       $$ = $2;
                }
        ;
 
 %%
 
-void yyerrorf(char const *s, ...)
+void print_error(char const *fmt, ...)
 {
-       const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
        va_list va;
-       va_start(va, s);
-
-       if (strcmp(fname, "-") == 0)
-               fname = "stdin";
 
-       fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
-       vfprintf(stderr, s, va);
-       fprintf(stderr, "\n");
+       va_start(va, fmt);
+       srcpos_verror(&yylloc, fmt, va);
+       va_end(va);
 
        treesource_error = 1;
-       va_end(va);
 }
 
-void yyerror (char const *s)
-{
-       yyerrorf("%s", s);
+void yyerror(char const *s) {
+       print_error("%s", s);
 }
 
 static unsigned long long eval_literal(const char *s, int base, int bits)
@@ -369,11 +335,11 @@ static unsigned long long eval_literal(const char *s, int base, int bits)
        errno = 0;
        val = strtoull(s, &e, base);
        if (*e)
-               yyerror("bad characters in literal");
+               print_error("bad characters in literal");
        else if ((errno == ERANGE)
                 || ((bits < 64) && (val >= (1ULL << bits))))
-               yyerror("literal out of range");
+               print_error("literal out of range");
        else if (errno != 0)
-               yyerror("bad literal");
+               print_error("bad literal");
        return val;
 }
index d8fd43b4ac1a517a339e30e095f2a28544a1b906..cbc0193098e4e83ea4628facb1d86dcbcc54be18 100644 (file)
@@ -30,30 +30,7 @@ int quiet;           /* Level of quietness */
 int reservenum;                /* Number of memory reservation slots */
 int minsize;           /* Minimum blob size */
 int padsize;           /* Additional padding to blob */
-
-char *join_path(const char *path, const char *name)
-{
-       int lenp = strlen(path);
-       int lenn = strlen(name);
-       int len;
-       int needslash = 1;
-       char *str;
-
-       len = lenp + lenn + 2;
-       if ((lenp > 0) && (path[lenp-1] == '/')) {
-               needslash = 0;
-               len--;
-       }
-
-       str = xmalloc(len);
-       memcpy(str, path, lenp);
-       if (needslash) {
-               str[lenp] = '/';
-               lenp++;
-       }
-       memcpy(str+lenp, name, lenn+1);
-       return str;
-}
+int phandle_format = PHANDLE_BOTH;     /* Use linux,phandle or phandle properties */
 
 static void fill_fullpaths(struct node *tree, const char *prefix)
 {
@@ -104,8 +81,15 @@ static void  __attribute__ ((noreturn)) usage(void)
        fprintf(stderr, "\t\tSet the physical boot cpu\n");
        fprintf(stderr, "\t-f\n");
        fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
+       fprintf(stderr, "\t-s\n");
+       fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n");
        fprintf(stderr, "\t-v\n");
        fprintf(stderr, "\t\tPrint DTC version and exit\n");
+       fprintf(stderr, "\t-H <phandle format>\n");
+       fprintf(stderr, "\t\tphandle formats are:\n");
+       fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n");
+       fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n");
+       fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n");
        exit(3);
 }
 
@@ -115,7 +99,7 @@ int main(int argc, char *argv[])
        const char *inform = "dts";
        const char *outform = "dts";
        const char *outname = "-";
-       int force = 0, check = 0;
+       int force = 0, check = 0, sort = 0;
        const char *arg;
        int opt;
        FILE *outf = NULL;
@@ -127,7 +111,7 @@ int main(int argc, char *argv[])
        minsize    = 0;
        padsize    = 0;
 
-       while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:v")) != EOF) {
+       while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:vH:s")) != EOF) {
                switch (opt) {
                case 'I':
                        inform = optarg;
@@ -165,6 +149,22 @@ int main(int argc, char *argv[])
                case 'v':
                        printf("Version: %s\n", DTC_VERSION);
                        exit(0);
+               case 'H':
+                       if (streq(optarg, "legacy"))
+                               phandle_format = PHANDLE_LEGACY;
+                       else if (streq(optarg, "epapr"))
+                               phandle_format = PHANDLE_EPAPR;
+                       else if (streq(optarg, "both"))
+                               phandle_format = PHANDLE_BOTH;
+                       else
+                               die("Invalid argument \"%s\" to -H option\n",
+                                   optarg);
+                       break;
+
+               case 's':
+                       sort = 1;
+                       break;
+
                case 'h':
                default:
                        usage();
@@ -182,6 +182,9 @@ int main(int argc, char *argv[])
        if (minsize && padsize)
                die("Can't set both -p and -S\n");
 
+       if (minsize)
+               fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n");
+
        fprintf(stderr, "DTC: %s->%s  on file \"%s\"\n",
                inform, outform, arg);
 
@@ -200,6 +203,8 @@ int main(int argc, char *argv[])
        fill_fullpaths(bi->dt, "");
        process_checks(force, bi);
 
+       if (sort)
+               sort_tree(bi);
 
        if (streq(outname, "-")) {
                outf = stdout;
index 08d54c8700863a84ab08c26ef699af4bce99c431..f37c97eb3dfc2ca1694e6c3a2bb053949faa12e5 100644 (file)
 #include <libfdt_env.h>
 #include <fdt.h>
 
+#include "util.h"
+
+#ifdef DEBUG
+#define debug(fmt,args...)     printf(fmt, ##args)
+#else
+#define debug(fmt,args...)
+#endif
+
+
 #define DEFAULT_FDT_VERSION    17
+
 /*
  * Command line options
  */
@@ -42,36 +52,11 @@ extern int quiet;           /* Level of quietness */
 extern int reservenum;         /* Number of memory reservation slots */
 extern int minsize;            /* Minimum blob size */
 extern int padsize;            /* Additional padding to blob */
+extern int phandle_format;     /* Use linux,phandle or phandle properties */
 
-static inline void __attribute__((noreturn)) die(char * str, ...)
-{
-       va_list ap;
-
-       va_start(ap, str);
-       fprintf(stderr, "FATAL ERROR: ");
-       vfprintf(stderr, str, ap);
-       exit(1);
-}
-
-static inline void *xmalloc(size_t len)
-{
-       void *new = malloc(len);
-
-       if (! new)
-               die("malloc() failed\n");
-
-       return new;
-}
-
-static inline void *xrealloc(void *p, size_t len)
-{
-       void *new = realloc(p, len);
-
-       if (! new)
-               die("realloc() failed (len=%d)\n", len);
-
-       return new;
-}
+#define PHANDLE_LEGACY 0x1
+#define PHANDLE_EPAPR  0x2
+#define PHANDLE_BOTH   0x3
 
 typedef uint32_t cell_t;
 
@@ -140,13 +125,18 @@ int data_is_one_string(struct data d);
 #define MAX_NODENAME_LEN       31
 
 /* Live trees */
+struct label {
+       char *label;
+       struct label *next;
+};
+
 struct property {
        char *name;
        struct data val;
 
        struct property *next;
 
-       char *label;
+       struct label *labels;
 };
 
 struct node {
@@ -163,22 +153,28 @@ struct node {
        cell_t phandle;
        int addr_cells, size_cells;
 
-       char *label;
+       struct label *labels;
 };
 
+#define for_each_label(l0, l) \
+       for ((l) = (l0); (l); (l) = (l)->next)
+
 #define for_each_property(n, p) \
        for ((p) = (n)->proplist; (p); (p) = (p)->next)
 
 #define for_each_child(n, c)   \
        for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
 
-struct property *build_property(char *name, struct data val, char *label);
+void add_label(struct label **labels, char *label);
+
+struct property *build_property(char *name, struct data val);
 struct property *chain_property(struct property *first, struct property *list);
 struct property *reverse_properties(struct property *first);
 
 struct node *build_node(struct property *proplist, struct node *children);
-struct node *name_node(struct node *node, char *name, char *label);
+struct node *name_node(struct node *node, char *name);
 struct node *chain_node(struct node *first, struct node *list);
+struct node *merge_nodes(struct node *old_node, struct node *new_node);
 
 void add_property(struct node *node, struct property *prop);
 void add_child(struct node *parent, struct node *child);
@@ -186,6 +182,10 @@ void add_child(struct node *parent, struct node *child);
 const char *get_unitname(struct node *node);
 struct property *get_property(struct node *node, const char *propname);
 cell_t propval_cell(struct property *prop);
+struct property *get_property_by_label(struct node *tree, const char *label,
+                                      struct node **node);
+struct marker *get_marker_label(struct node *tree, const char *label,
+                               struct node **node, struct property **prop);
 struct node *get_subnode(struct node *node, const char *nodename);
 struct node *get_node_by_path(struct node *tree, const char *path);
 struct node *get_node_by_label(struct node *tree, const char *label);
@@ -193,6 +193,8 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
 struct node *get_node_by_ref(struct node *tree, const char *ref);
 cell_t get_node_phandle(struct node *root, struct node *node);
 
+uint32_t guess_boot_cpuid(struct node *tree);
+
 /* Boot info (tree plus memreserve information */
 
 struct reserve_info {
@@ -200,10 +202,10 @@ struct reserve_info {
 
        struct reserve_info *next;
 
-       char *label;
+       struct label *labels;
 };
 
-struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len, char *label);
+struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len);
 struct reserve_info *chain_reserve_entry(struct reserve_info *first,
                                         struct reserve_info *list);
 struct reserve_info *add_reserve_entry(struct reserve_info *list,
@@ -218,6 +220,7 @@ struct boot_info {
 
 struct boot_info *build_boot_info(struct reserve_info *reservelist,
                                  struct node *tree, uint32_t boot_cpuid_phys);
+void sort_tree(struct boot_info *bi);
 
 /* Checks */
 
@@ -239,8 +242,4 @@ struct boot_info *dt_from_source(const char *f);
 
 struct boot_info *dt_from_fs(const char *dirname);
 
-/* misc */
-
-char *join_path(const char *path, const char *name);
-
 #endif /* _DTC_H */
index 76acd28c068db81195548369019b577d4aee5ddb..ead0332c87e1b1e613507c79bbcda2aa87998309 100644 (file)
@@ -52,9 +52,9 @@ struct emitter {
        void (*string)(void *, char *, int);
        void (*align)(void *, int);
        void (*data)(void *, struct data);
-       void (*beginnode)(void *, const char *);
-       void (*endnode)(void *, const char *);
-       void (*property)(void *, const char *);
+       void (*beginnode)(void *, struct label *labels);
+       void (*endnode)(void *, struct label *labels);
+       void (*property)(void *, struct label *labels);
 };
 
 static void bin_emit_cell(void *e, cell_t val)
@@ -89,17 +89,17 @@ static void bin_emit_data(void *e, struct data d)
        *dtbuf = data_append_data(*dtbuf, d.val, d.len);
 }
 
-static void bin_emit_beginnode(void *e, const char *label)
+static void bin_emit_beginnode(void *e, struct label *labels)
 {
        bin_emit_cell(e, FDT_BEGIN_NODE);
 }
 
-static void bin_emit_endnode(void *e, const char *label)
+static void bin_emit_endnode(void *e, struct label *labels)
 {
        bin_emit_cell(e, FDT_END_NODE);
 }
 
-static void bin_emit_property(void *e, const char *label)
+static void bin_emit_property(void *e, struct label *labels)
 {
        bin_emit_cell(e, FDT_PROP);
 }
@@ -127,11 +127,21 @@ static void emit_offset_label(FILE *f, const char *label, int offset)
        fprintf(f, "%s\t= . + %d\n", label, offset);
 }
 
+#define ASM_EMIT_BELONG(f, fmt, ...) \
+       { \
+               fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \
+               fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \
+               fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \
+               fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \
+       }
+
 static void asm_emit_cell(void *e, cell_t val)
 {
        FILE *f = e;
 
-       fprintf(f, "\t.long\t0x%x\n", val);
+       fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
+               (val >> 24) & 0xff, (val >> 16) & 0xff,
+               (val >> 8) & 0xff, val & 0xff);
 }
 
 static void asm_emit_string(void *e, char *str, int len)
@@ -156,7 +166,7 @@ static void asm_emit_align(void *e, int a)
 {
        FILE *f = e;
 
-       fprintf(f, "\t.balign\t%d\n", a);
+       fprintf(f, "\t.balign\t%d, 0\n", a);
 }
 
 static void asm_emit_data(void *e, struct data d)
@@ -169,8 +179,7 @@ static void asm_emit_data(void *e, struct data d)
                emit_offset_label(f, m->ref, m->offset);
 
        while ((d.len - off) >= sizeof(uint32_t)) {
-               fprintf(f, "\t.long\t0x%x\n",
-                       fdt32_to_cpu(*((uint32_t *)(d.val+off))));
+               asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off))));
                off += sizeof(uint32_t);
        }
 
@@ -182,37 +191,43 @@ static void asm_emit_data(void *e, struct data d)
        assert(off == d.len);
 }
 
-static void asm_emit_beginnode(void *e, const char *label)
+static void asm_emit_beginnode(void *e, struct label *labels)
 {
        FILE *f = e;
+       struct label *l;
 
-       if (label) {
-               fprintf(f, "\t.globl\t%s\n", label);
-               fprintf(f, "%s:\n", label);
+       for_each_label(labels, l) {
+               fprintf(f, "\t.globl\t%s\n", l->label);
+               fprintf(f, "%s:\n", l->label);
        }
-       fprintf(f, "\t.long\tFDT_BEGIN_NODE\n");
+       fprintf(f, "\t/* FDT_BEGIN_NODE */\n");
+       asm_emit_cell(e, FDT_BEGIN_NODE);
 }
 
-static void asm_emit_endnode(void *e, const char *label)
+static void asm_emit_endnode(void *e, struct label *labels)
 {
        FILE *f = e;
+       struct label *l;
 
-       fprintf(f, "\t.long\tFDT_END_NODE\n");
-       if (label) {
-               fprintf(f, "\t.globl\t%s_end\n", label);
-               fprintf(f, "%s_end:\n", label);
+       fprintf(f, "\t/* FDT_END_NODE */\n");
+       asm_emit_cell(e, FDT_END_NODE);
+       for_each_label(labels, l) {
+               fprintf(f, "\t.globl\t%s_end\n", l->label);
+               fprintf(f, "%s_end:\n", l->label);
        }
 }
 
-static void asm_emit_property(void *e, const char *label)
+static void asm_emit_property(void *e, struct label *labels)
 {
        FILE *f = e;
+       struct label *l;
 
-       if (label) {
-               fprintf(f, "\t.globl\t%s\n", label);
-               fprintf(f, "%s:\n", label);
+       for_each_label(labels, l) {
+               fprintf(f, "\t.globl\t%s\n", l->label);
+               fprintf(f, "%s:\n", l->label);
        }
-       fprintf(f, "\t.long\tFDT_PROP\n");
+       fprintf(f, "\t/* FDT_PROP */\n");
+       asm_emit_cell(e, FDT_PROP);
 }
 
 static struct emitter asm_emitter = {
@@ -248,7 +263,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
        struct node *child;
        int seen_name_prop = 0;
 
-       emit->beginnode(etarget, tree->label);
+       emit->beginnode(etarget, tree->labels);
 
        if (vi->flags & FTF_FULLPATH)
                emit->string(etarget, tree->fullpath, 0);
@@ -265,7 +280,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
 
                nameoff = stringtable_insert(strbuf, prop->name);
 
-               emit->property(etarget, prop->label);
+               emit->property(etarget, prop->labels);
                emit->cell(etarget, prop->val.len);
                emit->cell(etarget, nameoff);
 
@@ -292,7 +307,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
                flatten_tree(child, emit, etarget, strbuf, vi);
        }
 
-       emit->endnode(etarget, tree->label);
+       emit->endnode(etarget, tree->labels);
 }
 
 static struct data flatten_reserve_list(struct reserve_info *reservelist,
@@ -413,10 +428,13 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
        if (padlen > 0)
                blob = data_append_zeroes(blob, padlen);
 
-       fwrite(blob.val, blob.len, 1, f);
-
-       if (ferror(f))
-               die("Error writing device tree blob: %s\n", strerror(errno));
+       if (fwrite(blob.val, blob.len, 1, f) != 1) {
+               if (ferror(f))
+                       die("Error writing device tree blob: %s\n",
+                           strerror(errno));
+               else
+                       die("Short write on device tree blob\n");
+       }
 
        /*
         * data_merge() frees the right-hand element so only the blob
@@ -455,39 +473,44 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
                die("Unknown device tree blob version %d\n", version);
 
        fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
-       fprintf(f, "#define FDT_MAGIC 0x%x\n", FDT_MAGIC);
-       fprintf(f, "#define FDT_BEGIN_NODE 0x%x\n", FDT_BEGIN_NODE);
-       fprintf(f, "#define FDT_END_NODE 0x%x\n", FDT_END_NODE);
-       fprintf(f, "#define FDT_PROP 0x%x\n", FDT_PROP);
-       fprintf(f, "#define FDT_END 0x%x\n", FDT_END);
-       fprintf(f, "\n");
 
        emit_label(f, symprefix, "blob_start");
        emit_label(f, symprefix, "header");
-       fprintf(f, "\t.long\tFDT_MAGIC\t\t\t\t/* magic */\n");
-       fprintf(f, "\t.long\t_%s_blob_abs_end - _%s_blob_start\t/* totalsize */\n",
-               symprefix, symprefix);
-       fprintf(f, "\t.long\t_%s_struct_start - _%s_blob_start\t/* off_dt_struct */\n",
+       fprintf(f, "\t/* magic */\n");
+       asm_emit_cell(f, FDT_MAGIC);
+       fprintf(f, "\t/* totalsize */\n");
+       ASM_EMIT_BELONG(f, "_%s_blob_abs_end - _%s_blob_start",
+                       symprefix, symprefix);
+       fprintf(f, "\t/* off_dt_struct */\n");
+       ASM_EMIT_BELONG(f, "_%s_struct_start - _%s_blob_start",
                symprefix, symprefix);
-       fprintf(f, "\t.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n",
+       fprintf(f, "\t/* off_dt_strings */\n");
+       ASM_EMIT_BELONG(f, "_%s_strings_start - _%s_blob_start",
                symprefix, symprefix);
-       fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n",
+       fprintf(f, "\t/* off_mem_rsvmap */\n");
+       ASM_EMIT_BELONG(f, "_%s_reserve_map - _%s_blob_start",
                symprefix, symprefix);
-       fprintf(f, "\t.long\t%d\t\t\t\t\t/* version */\n", vi->version);
-       fprintf(f, "\t.long\t%d\t\t\t\t\t/* last_comp_version */\n",
-               vi->last_comp_version);
-
-       if (vi->flags & FTF_BOOTCPUID)
-               fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n",
-                       bi->boot_cpuid_phys);
+       fprintf(f, "\t/* version */\n");
+       asm_emit_cell(f, vi->version);
+       fprintf(f, "\t/* last_comp_version */\n");
+       asm_emit_cell(f, vi->last_comp_version);
+
+       if (vi->flags & FTF_BOOTCPUID) {
+               fprintf(f, "\t/* boot_cpuid_phys */\n");
+               asm_emit_cell(f, bi->boot_cpuid_phys);
+       }
 
-       if (vi->flags & FTF_STRTABSIZE)
-               fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n",
-                       symprefix, symprefix);
+       if (vi->flags & FTF_STRTABSIZE) {
+               fprintf(f, "\t/* size_dt_strings */\n");
+               ASM_EMIT_BELONG(f, "_%s_strings_end - _%s_strings_start",
+                               symprefix, symprefix);
+       }
 
-       if (vi->flags & FTF_STRUCTSIZE)
-               fprintf(f, "\t.long\t_%s_struct_end - _%s_struct_start\t/* size_dt_struct */\n",
+       if (vi->flags & FTF_STRUCTSIZE) {
+               fprintf(f, "\t/* size_dt_struct */\n");
+               ASM_EMIT_BELONG(f, "_%s_struct_end - _%s_struct_start",
                        symprefix, symprefix);
+       }
 
        /*
         * Reserve map entries.
@@ -505,16 +528,17 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
         * as it appears .quad isn't available in some assemblers.
         */
        for (re = bi->reservelist; re; re = re->next) {
-               if (re->label) {
-                       fprintf(f, "\t.globl\t%s\n", re->label);
-                       fprintf(f, "%s:\n", re->label);
+               struct label *l;
+
+               for_each_label(re->labels, l) {
+                       fprintf(f, "\t.globl\t%s\n", l->label);
+                       fprintf(f, "%s:\n", l->label);
                }
-               fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
-                       (unsigned int)(re->re.address >> 32),
-                       (unsigned int)(re->re.address & 0xffffffff));
-               fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
-                       (unsigned int)(re->re.size >> 32),
-                       (unsigned int)(re->re.size & 0xffffffff));
+               ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
+               ASM_EMIT_BELONG(f, "0x%08x",
+                               (unsigned int)(re->re.address & 0xffffffff));
+               ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32));
+               ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff));
        }
        for (i = 0; i < reservenum; i++) {
                fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
@@ -524,7 +548,9 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
 
        emit_label(f, symprefix, "struct_start");
        flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
-       fprintf(f, "\t.long\tFDT_END\n");
+
+       fprintf(f, "\t/* FDT_END */\n");
+       asm_emit_cell(f, FDT_END);
        emit_label(f, symprefix, "struct_end");
 
        emit_label(f, symprefix, "strings_start");
@@ -601,7 +627,7 @@ static char *flat_read_string(struct inbuf *inb)
                len++;
        } while ((*p++) != '\0');
 
-       str = strdup(inb->ptr);
+       str = xstrdup(inb->ptr);
 
        inb->ptr += len;
 
@@ -643,7 +669,7 @@ static char *flat_read_stringtable(struct inbuf *inb, int offset)
                p++;
        }
 
-       return strdup(inb->base + offset);
+       return xstrdup(inb->base + offset);
 }
 
 static struct property *flat_read_property(struct inbuf *dtbuf,
@@ -663,7 +689,7 @@ static struct property *flat_read_property(struct inbuf *dtbuf,
 
        val = flat_read_data(dtbuf, proplen);
 
-       return build_property(name, val, NULL);
+       return build_property(name, val);
 }
 
 
@@ -688,7 +714,7 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
                if (re.size == 0)
                        break;
 
-               new = build_reserve_entry(re.address, re.size, NULL);
+               new = build_reserve_entry(re.address, re.size);
                reservelist = add_reserve_entry(reservelist, new);
        }
 
@@ -710,7 +736,7 @@ static char *nodename_from_path(const char *ppath, const char *cpath)
        if (!streq(ppath, "/"))
                plen++;
 
-       return strdup(cpath + plen);
+       return xstrdup(cpath + plen);
 }
 
 static struct node *unflatten_tree(struct inbuf *dtbuf,
@@ -776,7 +802,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
 
 struct boot_info *dt_from_blob(const char *fname)
 {
-       struct dtc_file *dtcf;
+       FILE *f;
        uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
        uint32_t off_dt, off_str, off_mem_rsvmap;
        int rc;
@@ -791,14 +817,14 @@ struct boot_info *dt_from_blob(const char *fname)
        uint32_t val;
        int flags = 0;
 
-       dtcf = dtc_open_file(fname, NULL);
+       f = srcfile_relative_open(fname, NULL);
 
-       rc = fread(&magic, sizeof(magic), 1, dtcf->file);
-       if (ferror(dtcf->file))
+       rc = fread(&magic, sizeof(magic), 1, f);
+       if (ferror(f))
                die("Error reading DT blob magic number: %s\n",
                    strerror(errno));
        if (rc < 1) {
-               if (feof(dtcf->file))
+               if (feof(f))
                        die("EOF reading DT blob magic number\n");
                else
                        die("Mysterious short read reading magic number\n");
@@ -808,11 +834,11 @@ struct boot_info *dt_from_blob(const char *fname)
        if (magic != FDT_MAGIC)
                die("Blob has incorrect magic number\n");
 
-       rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file);
-       if (ferror(dtcf->file))
+       rc = fread(&totalsize, sizeof(totalsize), 1, f);
+       if (ferror(f))
                die("Error reading DT blob size: %s\n", strerror(errno));
        if (rc < 1) {
-               if (feof(dtcf->file))
+               if (feof(f))
                        die("EOF reading DT blob size\n");
                else
                        die("Mysterious short read reading blob size\n");
@@ -832,12 +858,12 @@ struct boot_info *dt_from_blob(const char *fname)
        p = blob + sizeof(magic)  + sizeof(totalsize);
 
        while (sizeleft) {
-               if (feof(dtcf->file))
+               if (feof(f))
                        die("EOF before reading %d bytes of DT blob\n",
                            totalsize);
 
-               rc = fread(p, 1, sizeleft, dtcf->file);
-               if (ferror(dtcf->file))
+               rc = fread(p, 1, sizeleft, f);
+               if (ferror(f))
                        die("Error reading DT blob: %s\n",
                            strerror(errno));
 
@@ -900,7 +926,7 @@ struct boot_info *dt_from_blob(const char *fname)
 
        free(blob);
 
-       dtc_close_file(dtcf);
+       fclose(f);
 
        return build_boot_info(reservelist, tree, boot_cpuid_phys);
 }
index 8fe1bdf239f0f7a4d1e40baadf9cd8430c5176aa..f3774530170ab6ac7465ae31cb5777bbe48614d0 100644 (file)
@@ -58,10 +58,9 @@ static struct node *read_fstree(const char *dirname)
                                        "WARNING: Cannot open %s: %s\n",
                                        tmpnam, strerror(errno));
                        } else {
-                               prop = build_property(strdup(de->d_name),
+                               prop = build_property(xstrdup(de->d_name),
                                                      data_copy_file(pfile,
-                                                                    st.st_size),
-                                                     NULL);
+                                                                    st.st_size));
                                add_property(tree, prop);
                                fclose(pfile);
                        }
@@ -69,8 +68,7 @@ static struct node *read_fstree(const char *dirname)
                        struct node *newchild;
 
                        newchild = read_fstree(tmpnam);
-                       newchild = name_node(newchild, strdup(de->d_name),
-                                            NULL);
+                       newchild = name_node(newchild, xstrdup(de->d_name));
                        add_child(tree, newchild);
                }
 
@@ -86,8 +84,8 @@ struct boot_info *dt_from_fs(const char *dirname)
        struct node *tree;
 
        tree = read_fstree(dirname);
-       tree = name_node(tree, "", NULL);
+       tree = name_node(tree, "");
 
-       return build_boot_info(NULL, tree, 0);
+       return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
 }
 
index 0ca3de550b3ff7d1ef6d437849061238275b0d4d..c9209d5c999e48d77f39cb13a86ec49efd9c2b8a 100644 (file)
  * Tree building functions
  */
 
-struct property *build_property(char *name, struct data val, char *label)
+void add_label(struct label **labels, char *label)
+{
+       struct label *new;
+
+       /* Make sure the label isn't already there */
+       for_each_label(*labels, new)
+               if (streq(new->label, label))
+                       return;
+
+       new = xmalloc(sizeof(*new));
+       new->label = label;
+       new->next = *labels;
+       *labels = new;
+}
+
+struct property *build_property(char *name, struct data val)
 {
        struct property *new = xmalloc(sizeof(*new));
 
+       memset(new, 0, sizeof(*new));
+
        new->name = name;
        new->val = val;
 
-       new->next = NULL;
-
-       new->label = label;
-
        return new;
 }
 
@@ -78,17 +91,82 @@ struct node *build_node(struct property *proplist, struct node *children)
        return new;
 }
 
-struct node *name_node(struct node *node, char *name, char * label)
+struct node *name_node(struct node *node, char *name)
 {
        assert(node->name == NULL);
 
        node->name = name;
 
-       node->label = label;
-
        return node;
 }
 
+struct node *merge_nodes(struct node *old_node, struct node *new_node)
+{
+       struct property *new_prop, *old_prop;
+       struct node *new_child, *old_child;
+       struct label *l;
+
+       /* Add new node labels to old node */
+       for_each_label(new_node->labels, l)
+               add_label(&old_node->labels, l->label);
+
+       /* Move properties from the new node to the old node.  If there
+        * is a collision, replace the old value with the new */
+       while (new_node->proplist) {
+               /* Pop the property off the list */
+               new_prop = new_node->proplist;
+               new_node->proplist = new_prop->next;
+               new_prop->next = NULL;
+
+               /* Look for a collision, set new value if there is */
+               for_each_property(old_node, old_prop) {
+                       if (streq(old_prop->name, new_prop->name)) {
+                               /* Add new labels to old property */
+                               for_each_label(new_prop->labels, l)
+                                       add_label(&old_prop->labels, l->label);
+
+                               old_prop->val = new_prop->val;
+                               free(new_prop);
+                               new_prop = NULL;
+                               break;
+                       }
+               }
+
+               /* if no collision occurred, add property to the old node. */
+               if (new_prop)
+                       add_property(old_node, new_prop);
+       }
+
+       /* Move the override child nodes into the primary node.  If
+        * there is a collision, then merge the nodes. */
+       while (new_node->children) {
+               /* Pop the child node off the list */
+               new_child = new_node->children;
+               new_node->children = new_child->next_sibling;
+               new_child->parent = NULL;
+               new_child->next_sibling = NULL;
+
+               /* Search for a collision.  Merge if there is */
+               for_each_child(old_node, old_child) {
+                       if (streq(old_child->name, new_child->name)) {
+                               merge_nodes(old_child, new_child);
+                               new_child = NULL;
+                               break;
+                       }
+               }
+
+               /* if no collision occured, add child to the old node. */
+               if (new_child)
+                       add_child(old_node, new_child);
+       }
+
+       /* The new node contents are now merged into the old node.  Free
+        * the new node. */
+       free(new_node);
+
+       return old_node;
+}
+
 struct node *chain_node(struct node *first, struct node *list)
 {
        assert(first->next_sibling == NULL);
@@ -124,18 +202,15 @@ void add_child(struct node *parent, struct node *child)
        *p = child;
 }
 
-struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size,
-                                        char *label)
+struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
 {
        struct reserve_info *new = xmalloc(sizeof(*new));
 
+       memset(new, 0, sizeof(*new));
+
        new->re.address = address;
        new->re.size = size;
 
-       new->next = NULL;
-
-       new->label = label;
-
        return new;
 }
 
@@ -208,6 +283,60 @@ cell_t propval_cell(struct property *prop)
        return fdt32_to_cpu(*((cell_t *)prop->val.val));
 }
 
+struct property *get_property_by_label(struct node *tree, const char *label,
+                                      struct node **node)
+{
+       struct property *prop;
+       struct node *c;
+
+       *node = tree;
+
+       for_each_property(tree, prop) {
+               struct label *l;
+
+               for_each_label(prop->labels, l)
+                       if (streq(l->label, label))
+                               return prop;
+       }
+
+       for_each_child(tree, c) {
+               prop = get_property_by_label(c, label, node);
+               if (prop)
+                       return prop;
+       }
+
+       *node = NULL;
+       return NULL;
+}
+
+struct marker *get_marker_label(struct node *tree, const char *label,
+                               struct node **node, struct property **prop)
+{
+       struct marker *m;
+       struct property *p;
+       struct node *c;
+
+       *node = tree;
+
+       for_each_property(tree, p) {
+               *prop = p;
+               m = p->val.markers;
+               for_each_marker_of_type(m, LABEL)
+                       if (streq(m->ref, label))
+                               return m;
+       }
+
+       for_each_child(tree, c) {
+               m = get_marker_label(c, label, node, prop);
+               if (m)
+                       return m;
+       }
+
+       *prop = NULL;
+       *node = NULL;
+       return NULL;
+}
+
 struct node *get_subnode(struct node *node, const char *nodename)
 {
        struct node *child;
@@ -245,11 +374,13 @@ struct node *get_node_by_path(struct node *tree, const char *path)
 struct node *get_node_by_label(struct node *tree, const char *label)
 {
        struct node *child, *node;
+       struct label *l;
 
        assert(label && (strlen(label) > 0));
 
-       if (tree->label && streq(tree->label, label))
-               return tree;
+       for_each_label(tree->labels, l)
+               if (streq(l->label, label))
+                       return tree;
 
        for_each_child(tree, child) {
                node = get_node_by_label(child, label);
@@ -293,16 +424,186 @@ cell_t get_node_phandle(struct node *root, struct node *node)
        if ((node->phandle != 0) && (node->phandle != -1))
                return node->phandle;
 
-       assert(! get_property(node, "linux,phandle"));
-
        while (get_node_by_phandle(root, phandle))
                phandle++;
 
        node->phandle = phandle;
-       add_property(node,
-                    build_property("linux,phandle",
-                                   data_append_cell(empty_data, phandle),
-                                   NULL));
+
+       if (!get_property(node, "linux,phandle")
+           && (phandle_format & PHANDLE_LEGACY))
+               add_property(node,
+                            build_property("linux,phandle",
+                                           data_append_cell(empty_data, phandle)));
+
+       if (!get_property(node, "phandle")
+           && (phandle_format & PHANDLE_EPAPR))
+               add_property(node,
+                            build_property("phandle",
+                                           data_append_cell(empty_data, phandle)));
+
+       /* If the node *does* have a phandle property, we must
+        * be dealing with a self-referencing phandle, which will be
+        * fixed up momentarily in the caller */
 
        return node->phandle;
 }
+
+uint32_t guess_boot_cpuid(struct node *tree)
+{
+       struct node *cpus, *bootcpu;
+       struct property *reg;
+
+       cpus = get_node_by_path(tree, "/cpus");
+       if (!cpus)
+               return 0;
+
+
+       bootcpu = cpus->children;
+       if (!bootcpu)
+               return 0;
+
+       reg = get_property(bootcpu, "reg");
+       if (!reg || (reg->val.len != sizeof(uint32_t)))
+               return 0;
+
+       /* FIXME: Sanity check node? */
+
+       return propval_cell(reg);
+}
+
+static int cmp_reserve_info(const void *ax, const void *bx)
+{
+       const struct reserve_info *a, *b;
+
+       a = *((const struct reserve_info * const *)ax);
+       b = *((const struct reserve_info * const *)bx);
+
+       if (a->re.address < b->re.address)
+               return -1;
+       else if (a->re.address > b->re.address)
+               return 1;
+       else if (a->re.size < b->re.size)
+               return -1;
+       else if (a->re.size > b->re.size)
+               return 1;
+       else
+               return 0;
+}
+
+static void sort_reserve_entries(struct boot_info *bi)
+{
+       struct reserve_info *ri, **tbl;
+       int n = 0, i = 0;
+
+       for (ri = bi->reservelist;
+            ri;
+            ri = ri->next)
+               n++;
+
+       if (n == 0)
+               return;
+
+       tbl = xmalloc(n * sizeof(*tbl));
+
+       for (ri = bi->reservelist;
+            ri;
+            ri = ri->next)
+               tbl[i++] = ri;
+
+       qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
+
+       bi->reservelist = tbl[0];
+       for (i = 0; i < (n-1); i++)
+               tbl[i]->next = tbl[i+1];
+       tbl[n-1]->next = NULL;
+
+       free(tbl);
+}
+
+static int cmp_prop(const void *ax, const void *bx)
+{
+       const struct property *a, *b;
+
+       a = *((const struct property * const *)ax);
+       b = *((const struct property * const *)bx);
+
+       return strcmp(a->name, b->name);
+}
+
+static void sort_properties(struct node *node)
+{
+       int n = 0, i = 0;
+       struct property *prop, **tbl;
+
+       for_each_property(node, prop)
+               n++;
+
+       if (n == 0)
+               return;
+
+       tbl = xmalloc(n * sizeof(*tbl));
+
+       for_each_property(node, prop)
+               tbl[i++] = prop;
+
+       qsort(tbl, n, sizeof(*tbl), cmp_prop);
+
+       node->proplist = tbl[0];
+       for (i = 0; i < (n-1); i++)
+               tbl[i]->next = tbl[i+1];
+       tbl[n-1]->next = NULL;
+
+       free(tbl);
+}
+
+static int cmp_subnode(const void *ax, const void *bx)
+{
+       const struct node *a, *b;
+
+       a = *((const struct node * const *)ax);
+       b = *((const struct node * const *)bx);
+
+       return strcmp(a->name, b->name);
+}
+
+static void sort_subnodes(struct node *node)
+{
+       int n = 0, i = 0;
+       struct node *subnode, **tbl;
+
+       for_each_child(node, subnode)
+               n++;
+
+       if (n == 0)
+               return;
+
+       tbl = xmalloc(n * sizeof(*tbl));
+
+       for_each_child(node, subnode)
+               tbl[i++] = subnode;
+
+       qsort(tbl, n, sizeof(*tbl), cmp_subnode);
+
+       node->children = tbl[0];
+       for (i = 0; i < (n-1); i++)
+               tbl[i]->next_sibling = tbl[i+1];
+       tbl[n-1]->next_sibling = NULL;
+
+       free(tbl);
+}
+
+static void sort_node(struct node *node)
+{
+       struct node *c;
+
+       sort_properties(node);
+       sort_subnodes(node);
+       for_each_child(node, c)
+               sort_node(c);
+}
+
+void sort_tree(struct boot_info *bi)
+{
+       sort_reserve_entries(bi);
+       sort_node(bi->dt);
+}
index 9641b7628b4de60b8d476f5329334b6dc6a10144..2dbc874288ca1b7487dd423d630cb7ac3b63e50f 100644 (file)
  *                                                                   USA
  */
 
+#define _GNU_SOURCE
+
+#include <stdio.h>
+
 #include "dtc.h"
 #include "srcpos.h"
 
-/*
- * Like yylineno, this is the current open file pos.
- */
 
-struct dtc_file *srcpos_file;
+static char *dirname(const char *path)
+{
+       const char *slash = strrchr(path, '/');
+
+       if (slash) {
+               int len = slash - path;
+               char *dir = xmalloc(len + 1);
+
+               memcpy(dir, path, len);
+               dir[len] = '\0';
+               return dir;
+       }
+       return NULL;
+}
+
+struct srcfile_state *current_srcfile; /* = NULL */
 
-static int dtc_open_one(struct dtc_file *file,
-                        const char *search,
-                        const char *fname)
+/* Detect infinite include recursion. */
+#define MAX_SRCFILE_DEPTH     (100)
+static int srcfile_depth; /* = 0 */
+
+FILE *srcfile_relative_open(const char *fname, char **fullnamep)
 {
+       FILE *f;
        char *fullname;
 
-       if (search) {
-               fullname = xmalloc(strlen(search) + strlen(fname) + 2);
-
-               strcpy(fullname, search);
-               strcat(fullname, "/");
-               strcat(fullname, fname);
+       if (streq(fname, "-")) {
+               f = stdin;
+               fullname = xstrdup("<stdin>");
        } else {
-               fullname = strdup(fname);
+               if (!current_srcfile || !current_srcfile->dir
+                   || (fname[0] == '/'))
+                       fullname = xstrdup(fname);
+               else
+                       fullname = join_path(current_srcfile->dir, fname);
+
+               f = fopen(fullname, "r");
+               if (!f)
+                       die("Couldn't open \"%s\": %s\n", fname,
+                           strerror(errno));
        }
 
-       file->file = fopen(fullname, "r");
-       if (!file->file) {
+       if (fullnamep)
+               *fullnamep = fullname;
+       else
                free(fullname);
-               return 0;
-       }
 
-       file->name = fullname;
-       return 1;
+       return f;
 }
 
+void srcfile_push(const char *fname)
+{
+       struct srcfile_state *srcfile;
+
+       if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
+               die("Includes nested too deeply");
+
+       srcfile = xmalloc(sizeof(*srcfile));
+
+       srcfile->f = srcfile_relative_open(fname, &srcfile->name);
+       srcfile->dir = dirname(srcfile->name);
+       srcfile->prev = current_srcfile;
+
+       srcfile->lineno = 1;
+       srcfile->colno = 1;
+
+       current_srcfile = srcfile;
+}
 
-struct dtc_file *dtc_open_file(const char *fname,
-                               const struct search_path *search)
+int srcfile_pop(void)
 {
-       static const struct search_path default_search = { NULL, NULL, NULL };
+       struct srcfile_state *srcfile = current_srcfile;
 
-       struct dtc_file *file;
-       const char *slash;
+       assert(srcfile);
 
-       file = xmalloc(sizeof(struct dtc_file));
+       current_srcfile = srcfile->prev;
 
-       slash = strrchr(fname, '/');
-       if (slash) {
-               char *dir = xmalloc(slash - fname + 1);
+       if (fclose(srcfile->f))
+               die("Error closing \"%s\": %s\n", srcfile->name,
+                   strerror(errno));
 
-               memcpy(dir, fname, slash - fname);
-               dir[slash - fname] = 0;
-               file->dir = dir;
-       } else {
-               file->dir = NULL;
-       }
+       /* FIXME: We allow the srcfile_state structure to leak,
+        * because it could still be referenced from a location
+        * variable being carried through the parser somewhere.  To
+        * fix this we could either allocate all the files from a
+        * table, or use a pool allocator. */
 
-       if (streq(fname, "-")) {
-               file->name = "stdin";
-               file->file = stdin;
-               return file;
-       }
+       return current_srcfile ? 1 : 0;
+}
 
-       if (fname[0] == '/') {
-               file->file = fopen(fname, "r");
-               if (!file->file)
-                       goto fail;
+/*
+ * The empty source position.
+ */
 
-               file->name = strdup(fname);
-               return file;
-       }
+struct srcpos srcpos_empty = {
+       .first_line = 0,
+       .first_column = 0,
+       .last_line = 0,
+       .last_column = 0,
+       .file = NULL,
+};
 
-       if (!search)
-               search = &default_search;
+#define TAB_SIZE      8
 
-       while (search) {
-               if (dtc_open_one(file, search->dir, fname))
-                       return file;
+void srcpos_update(struct srcpos *pos, const char *text, int len)
+{
+       int i;
+
+       pos->file = current_srcfile;
+
+       pos->first_line = current_srcfile->lineno;
+       pos->first_column = current_srcfile->colno;
+
+       for (i = 0; i < len; i++)
+               if (text[i] == '\n') {
+                       current_srcfile->lineno++;
+                       current_srcfile->colno = 1;
+               } else if (text[i] == '\t') {
+                       current_srcfile->colno =
+                               ALIGN(current_srcfile->colno, TAB_SIZE);
+               } else {
+                       current_srcfile->colno++;
+               }
+
+       pos->last_line = current_srcfile->lineno;
+       pos->last_column = current_srcfile->colno;
+}
 
-               if (errno != ENOENT)
-                       goto fail;
+struct srcpos *
+srcpos_copy(struct srcpos *pos)
+{
+       struct srcpos *pos_new;
 
-               search = search->next;
-       }
+       pos_new = xmalloc(sizeof(struct srcpos));
+       memcpy(pos_new, pos, sizeof(struct srcpos));
+
+       return pos_new;
+}
+
+
+
+void
+srcpos_dump(struct srcpos *pos)
+{
+       printf("file        : \"%s\"\n",
+              pos->file ? (char *) pos->file : "<no file>");
+       printf("first_line  : %d\n", pos->first_line);
+       printf("first_column: %d\n", pos->first_column);
+       printf("last_line   : %d\n", pos->last_line);
+       printf("last_column : %d\n", pos->last_column);
+       printf("file        : %s\n", pos->file->name);
+}
 
-fail:
-       die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
+
+char *
+srcpos_string(struct srcpos *pos)
+{
+       const char *fname = "<no-file>";
+       char *pos_str;
+       int rc;
+
+       if (pos)
+               fname = pos->file->name;
+
+
+       if (pos->first_line != pos->last_line)
+               rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
+                             pos->first_line, pos->first_column,
+                             pos->last_line, pos->last_column);
+       else if (pos->first_column != pos->last_column)
+               rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
+                             pos->first_line, pos->first_column,
+                             pos->last_column);
+       else
+               rc = asprintf(&pos_str, "%s:%d.%d", fname,
+                             pos->first_line, pos->first_column);
+
+       if (rc == -1)
+               die("Couldn't allocate in srcpos string");
+
+       return pos_str;
+}
+
+void
+srcpos_verror(struct srcpos *pos, char const *fmt, va_list va)
+{
+       const char *srcstr;
+
+       srcstr = srcpos_string(pos);
+
+       fprintf(stdout, "Error: %s ", srcstr);
+       vfprintf(stdout, fmt, va);
+       fprintf(stdout, "\n");
 }
 
-void dtc_close_file(struct dtc_file *file)
+void
+srcpos_error(struct srcpos *pos, char const *fmt, ...)
 {
-       if (fclose(file->file))
-               die("Error closing \"%s\": %s\n", file->name, strerror(errno));
+       va_list va;
+
+       va_start(va, fmt);
+       srcpos_verror(pos, fmt, va);
+       va_end(va);
+}
+
+
+void
+srcpos_warn(struct srcpos *pos, char const *fmt, ...)
+{
+       const char *srcstr;
+       va_list va;
+       va_start(va, fmt);
+
+       srcstr = srcpos_string(pos);
+
+       fprintf(stderr, "Warning: %s ", srcstr);
+       vfprintf(stderr, fmt, va);
+       fprintf(stderr, "\n");
 
-       free(file->dir);
-       free(file);
+       va_end(va);
 }
index e17c7c04db8ea4c17d4dfc94e7082b6eb9f296cb..bd7966e56a53672f8c5c34369067c38696e9e246 100644 (file)
  *                                                                   USA
  */
 
-/*
- * Augment the standard YYLTYPE with a filenum index into an
- * array of all opened filenames.
- */
+#ifndef _SRCPOS_H_
+#define _SRCPOS_H_
 
 #include <stdio.h>
 
-struct dtc_file {
+struct srcfile_state {
+       FILE *f;
+       char *name;
        char *dir;
-       const char *name;
-       FILE *file;
+       int lineno, colno;
+       struct srcfile_state *prev;
 };
 
-#if ! defined(YYLTYPE) && ! defined(YYLTYPE_IS_DECLARED)
-typedef struct YYLTYPE {
+extern struct srcfile_state *current_srcfile; /* = NULL */
+
+FILE *srcfile_relative_open(const char *fname, char **fullnamep);
+void srcfile_push(const char *fname);
+int srcfile_pop(void);
+
+struct srcpos {
     int first_line;
     int first_column;
     int last_line;
     int last_column;
-    struct dtc_file *file;
-} YYLTYPE;
-
-#define YYLTYPE_IS_DECLARED    1
-#define YYLTYPE_IS_TRIVIAL     1
-#endif
-
-/* Cater to old parser templates. */
-#ifndef YYID
-#define YYID(n)        (n)
-#endif
+    struct srcfile_state *file;
+};
 
-#define YYLLOC_DEFAULT(Current, Rhs, N)                                        \
-    do                                                                 \
-      if (YYID (N))                                                    \
-       {                                                               \
-         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
-         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
-         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
-         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
-         (Current).file         = YYRHSLOC (Rhs, N).file;              \
-       }                                                               \
-      else                                                             \
-       {                                                               \
-         (Current).first_line   = (Current).last_line   =              \
-           YYRHSLOC (Rhs, 0).last_line;                                \
-         (Current).first_column = (Current).last_column =              \
-           YYRHSLOC (Rhs, 0).last_column;                              \
-         (Current).file         = YYRHSLOC (Rhs, 0).file;              \
-       }                                                               \
-    while (YYID (0))
+#define YYLTYPE struct srcpos
 
+#define YYLLOC_DEFAULT(Current, Rhs, N)                                                \
+       do {                                                                    \
+               if (N) {                                                        \
+                       (Current).first_line = YYRHSLOC(Rhs, 1).first_line;     \
+                       (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
+                       (Current).last_line = YYRHSLOC(Rhs, N).last_line;       \
+                       (Current).last_column  = YYRHSLOC (Rhs, N).last_column; \
+                       (Current).file = YYRHSLOC(Rhs, N).file;                 \
+               } else {                                                        \
+                       (Current).first_line = (Current).last_line =            \
+                               YYRHSLOC(Rhs, 0).last_line;                     \
+                       (Current).first_column = (Current).last_column =        \
+                               YYRHSLOC(Rhs, 0).last_column;                   \
+                       (Current).file = YYRHSLOC (Rhs, 0).file;                \
+               }                                                               \
+       } while (0)
 
 
-extern void yyerror(char const *);
-extern void yyerrorf(char const *, ...) __attribute__((format(printf, 1, 2)));
+/*
+ * Fictional source position used for IR nodes that are
+ * created without otherwise knowing a true source position.
+ * For example,constant definitions from the command line.
+ */
+extern struct srcpos srcpos_empty;
 
-extern struct dtc_file *srcpos_file;
+extern void srcpos_update(struct srcpos *pos, const char *text, int len);
+extern struct srcpos *srcpos_copy(struct srcpos *pos);
+extern char *srcpos_string(struct srcpos *pos);
+extern void srcpos_dump(struct srcpos *pos);
 
-struct search_path {
-       const char *dir; /* NULL for current directory */
-       struct search_path *prev, *next;
-};
+extern void srcpos_verror(struct srcpos *pos, char const *, va_list va)
+     __attribute__((format(printf, 2, 0)));
+extern void srcpos_error(struct srcpos *pos, char const *, ...)
+     __attribute__((format(printf, 2, 3)));
+extern void srcpos_warn(struct srcpos *pos, char const *, ...)
+     __attribute__((format(printf, 2, 3)));
 
-extern struct dtc_file *dtc_open_file(const char *fname,
-                                      const struct search_path *search);
-extern void dtc_close_file(struct dtc_file *file);
+#endif /* _SRCPOS_H_ */
index 1521ff11bb972ed4c1d376b4baf0da38cd17bcf0..c09aafade313509740d662ed2c5f36a0d895a004 100644 (file)
@@ -32,8 +32,8 @@ struct boot_info *dt_from_source(const char *fname)
        the_boot_info = NULL;
        treesource_error = 0;
 
-       srcpos_file = dtc_open_file(fname, NULL);
-       yyin = srcpos_file->file;
+       srcfile_push(fname);
+       yyin = current_srcfile->f;
 
        if (yyparse() != 0)
                die("Unable to parse input tree\n");
@@ -63,26 +63,20 @@ static void write_propval_string(FILE *f, struct data val)
 {
        const char *str = val.val;
        int i;
-       int newchunk = 1;
        struct marker *m = val.markers;
 
        assert(str[val.len-1] == '\0');
 
+       while (m && (m->offset == 0)) {
+               if (m->type == LABEL)
+                       fprintf(f, "%s: ", m->ref);
+               m = m->next;
+       }
+       fprintf(f, "\"");
+
        for (i = 0; i < (val.len-1); i++) {
                char c = str[i];
 
-               if (newchunk) {
-                       while (m && (m->offset <= i)) {
-                               if (m->type == LABEL) {
-                                       assert(m->offset == i);
-                                       fprintf(f, "%s: ", m->ref);
-                               }
-                               m = m->next;
-                       }
-                       fprintf(f, "\"");
-                       newchunk = 0;
-               }
-
                switch (c) {
                case '\a':
                        fprintf(f, "\\a");
@@ -113,7 +107,14 @@ static void write_propval_string(FILE *f, struct data val)
                        break;
                case '\0':
                        fprintf(f, "\", ");
-                       newchunk = 1;
+                       while (m && (m->offset < i)) {
+                               if (m->type == LABEL) {
+                                       assert(m->offset == (i+1));
+                                       fprintf(f, "%s: ", m->ref);
+                               }
+                               m = m->next;
+                       }
+                       fprintf(f, "\"");
                        break;
                default:
                        if (isprint(c))
@@ -234,10 +235,11 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
 {
        struct property *prop;
        struct node *child;
+       struct label *l;
 
        write_prefix(f, level);
-       if (tree->label)
-               fprintf(f, "%s: ", tree->label);
+       for_each_label(tree->labels, l)
+               fprintf(f, "%s: ", l->label);
        if (tree->name && (*tree->name))
                fprintf(f, "%s {\n", tree->name);
        else
@@ -245,8 +247,8 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
 
        for_each_property(tree, prop) {
                write_prefix(f, level+1);
-               if (prop->label)
-                       fprintf(f, "%s: ", prop->label);
+               for_each_label(prop->labels, l)
+                       fprintf(f, "%s: ", l->label);
                fprintf(f, "%s", prop->name);
                write_propval(f, prop);
        }
@@ -266,8 +268,10 @@ void dt_to_source(FILE *f, struct boot_info *bi)
        fprintf(f, "/dts-v1/;\n\n");
 
        for (re = bi->reservelist; re; re = re->next) {
-               if (re->label)
-                       fprintf(f, "%s: ", re->label);
+               struct label *l;
+
+               for_each_label(re->labels, l)
+                       fprintf(f, "%s: ", l->label);
                fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
                        (unsigned long long)re->re.address,
                        (unsigned long long)re->re.size);
diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c
new file mode 100644 (file)
index 0000000..d7ac27d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "util.h"
+
+char *xstrdup(const char *s)
+{
+       int len = strlen(s) + 1;
+       char *dup = xmalloc(len);
+
+       memcpy(dup, s, len);
+
+       return dup;
+}
+
+char *join_path(const char *path, const char *name)
+{
+       int lenp = strlen(path);
+       int lenn = strlen(name);
+       int len;
+       int needslash = 1;
+       char *str;
+
+       len = lenp + lenn + 2;
+       if ((lenp > 0) && (path[lenp-1] == '/')) {
+               needslash = 0;
+               len--;
+       }
+
+       str = xmalloc(len);
+       memcpy(str, path, lenp);
+       if (needslash) {
+               str[lenp] = '/';
+               lenp++;
+       }
+       memcpy(str+lenp, name, lenn+1);
+       return str;
+}
diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h
new file mode 100644 (file)
index 0000000..9cead84
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef _UTIL_H
+#define _UTIL_H
+
+/*
+ * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ *  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
+ */
+
+static inline void __attribute__((noreturn)) die(char * str, ...)
+{
+       va_list ap;
+
+       va_start(ap, str);
+       fprintf(stderr, "FATAL ERROR: ");
+       vfprintf(stderr, str, ap);
+       exit(1);
+}
+
+static inline void *xmalloc(size_t len)
+{
+       void *new = malloc(len);
+
+       if (!new)
+               die("malloc() failed\n");
+
+       return new;
+}
+
+static inline void *xrealloc(void *p, size_t len)
+{
+       void *new = realloc(p, len);
+
+       if (!new)
+               die("realloc() failed (len=%d)\n", len);
+
+       return new;
+}
+
+extern char *xstrdup(const char *s);
+extern char *join_path(const char *path, const char *name);
+
+#endif /* _UTIL_H */
index 658ff42429d64eba3e37d34c1f66d760631814bd..6158b867df9989cca70d75b5b7b6416073791df4 100644 (file)
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.2.0"
+#define DTC_VERSION "DTC 1.2.0-g37c0b6a0"
index eaee44e66a43cba6686775dbd7ce628a2836d1d1..809b949e495b58267a180c31688ffd926e0adb49 100644 (file)
 
 
 #include <assert.h>
-#include <malloc.h>
+#include <stdlib.h>
 #include "genksyms.h"
 
 static int is_typedef;
index 10d7dc724b6d692a3ea283c4e0756798b03f73d6..09a265cd71939cba93839a53ba3b5ebf23574254 100644 (file)
@@ -24,7 +24,7 @@
 %{
 
 #include <assert.h>
-#include <malloc.h>
+#include <stdlib.h>
 #include "genksyms.h"
 
 static int is_typedef;
index 1ddcdd38d97ffb7c599c9ec940202ee18de55e64..978b42b3acd7e59519bdc74540a180da25e8c607 100755 (executable)
@@ -13,7 +13,7 @@ do_command()
        fi
 }
 
-archs=$(ls ${srctree}/arch)
+archs=${HDR_ARCH_LIST:-$(ls ${srctree}/arch)}
 
 for arch in ${archs}; do
        case ${arch} in
index 50d6cfd1fa778808b659a461884113de502f3f99..7957e7a5166a26b4ab29988273f69006354e03eb 100644 (file)
@@ -64,10 +64,10 @@ sub check_include
 
 sub check_declarations
 {
-       if ($line =~m/^\s*extern\b/) {
+       if ($line =~m/^(\s*extern|unsigned|char|short|int|long|void)\b/) {
                printf STDERR "$filename:$lineno: " .
-                             "userspace cannot call function or variable " .
-                             "defined in the kernel\n";
+                             "userspace cannot reference function or " .
+                             "variable defined in the kernel\n";
        }
 }
 
index 4ca3be3b2e50ef90c0a0e5e5e054aec081405b1b..efb3be10d428cb09b623b499cc5c03d728b57102 100644 (file)
@@ -45,6 +45,13 @@ foreach my $file (@files) {
        close $in;
 
        system $unifdef . " $tmpfile > $installdir/$file";
+       # unifdef will exit 0 on success, and will exit 1 when the
+       # file was processed successfully but no changes were made,
+       # so abort only when it's higher than that.
+       my $e = $? >> 8;
+       if ($e > 1) {
+               die "$tmpfile: $!\n";
+       }
        unlink $tmpfile;
 }
 exit 0;
index 5459a38be866064ae103ba5903859a6b53200d40..659326c3e89579b09f86077dbcbe5e1eb3a12d28 100644 (file)
@@ -529,8 +529,6 @@ int main(int ac, char **av)
                }
                break;
        case savedefconfig:
-               conf_read(NULL);
-               break;
        case silentoldconfig:
        case oldaskconfig:
        case oldconfig:
index 9df80114b47b6555d4401d2968ee3d5602409d62..61c35bf2d9cb93d690a40eafb0227006bec46151 100644 (file)
@@ -440,12 +440,11 @@ static void conf_write_string(bool headerfile, const char *name,
        fputs("\"\n", out);
 }
 
-static void conf_write_symbol(struct symbol *sym, enum symbol_type type,
-                              FILE *out, bool write_no)
+static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
 {
        const char *str;
 
-       switch (type) {
+       switch (sym->type) {
        case S_BOOLEAN:
        case S_TRISTATE:
                switch (sym_get_tristate_value(sym)) {
@@ -532,7 +531,7 @@ int conf_write_defconfig(const char *filename)
                                                goto next_menu;
                                }
                        }
-                       conf_write_symbol(sym, sym->type, out, true);
+                       conf_write_symbol(sym, out, true);
                }
 next_menu:
                if (menu->list != NULL) {
@@ -561,7 +560,6 @@ int conf_write(const char *name)
        const char *basename;
        const char *str;
        char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
-       enum symbol_type type;
        time_t now;
        int use_timestamp = 1;
        char *env;
@@ -633,14 +631,8 @@ int conf_write(const char *name)
                        if (!(sym->flags & SYMBOL_WRITE))
                                goto next;
                        sym->flags &= ~SYMBOL_WRITE;
-                       type = sym->type;
-                       if (type == S_TRISTATE) {
-                               sym_calc_value(modules_sym);
-                               if (modules_sym->curr.tri == no)
-                                       type = S_BOOLEAN;
-                       }
                        /* Write config symbol to file */
-                       conf_write_symbol(sym, type, out, true);
+                       conf_write_symbol(sym, out, true);
                }
 
 next:
@@ -833,8 +825,7 @@ int conf_write_autoconf(void)
                       " * Automatically generated C config: don't edit\n"
                       " * %s\n"
                       " * %s"
-                      " */\n"
-                      "#define AUTOCONF_INCLUDED\n",
+                      " */\n",
                       rootmenu.prompt->text, ctime(&now));
 
        for_all_symbols(i, sym) {
@@ -843,7 +834,7 @@ int conf_write_autoconf(void)
                        continue;
 
                /* write symbol to config file */
-               conf_write_symbol(sym, sym->type, out, false);
+               conf_write_symbol(sym, out, false);
 
                /* update autoconf and tristate files */
                switch (sym->type) {
@@ -946,7 +937,7 @@ static void randomize_choice_values(struct symbol *csym)
        int cnt, def;
 
        /*
-        * If choice is mod then we may have more items slected
+        * If choice is mod then we may have more items selected
         * and if no then no-one.
         * In both cases stop.
         */
@@ -1042,10 +1033,10 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)
 
        /*
         * We have different type of choice blocks.
-        * If curr.tri equal to mod then we can select several
+        * If curr.tri equals to mod then we can select several
         * choice symbols in one block.
         * In this case we do nothing.
-        * If curr.tri equal yes then only one symbol can be
+        * If curr.tri equals yes then only one symbol can be
         * selected in a choice block and we set it to yes,
         * and the rest to no.
         */
index 330e7c0048a85ea1939562e724eaa7f2326d56ab..001003452f6872aef385099f1d660ffa1054a288 100644 (file)
@@ -64,7 +64,7 @@ struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
        return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
 }
 
-struct expr *expr_copy(struct expr *org)
+struct expr *expr_copy(const struct expr *org)
 {
        struct expr *e;
 
@@ -1013,6 +1013,48 @@ int expr_compare_type(enum expr_type t1, enum expr_type t2)
 #endif
 }
 
+static inline struct expr *
+expr_get_leftmost_symbol(const struct expr *e)
+{
+
+       if (e == NULL)
+               return NULL;
+
+       while (e->type != E_SYMBOL)
+               e = e->left.expr;
+
+       return expr_copy(e);
+}
+
+/*
+ * Given expression `e1' and `e2', returns the leaf of the longest
+ * sub-expression of `e1' not containing 'e2.
+ */
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
+{
+       struct expr *ret;
+
+       switch (e1->type) {
+       case E_OR:
+               return expr_alloc_and(
+                   expr_simplify_unmet_dep(e1->left.expr, e2),
+                   expr_simplify_unmet_dep(e1->right.expr, e2));
+       case E_AND: {
+               struct expr *e;
+               e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
+               e = expr_eliminate_dups(e);
+               ret = (!expr_eq(e, e1)) ? e1 : NULL;
+               expr_free(e);
+               break;
+               }
+       default:
+               ret = e1;
+               break;
+       }
+
+       return expr_get_leftmost_symbol(ret);
+}
+
 void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
 {
        if (!e) {
index e57826ced3800bb596945a708b648d3f68006dec..3d238db4976405fee6aa122c3582e4a717a25315 100644 (file)
@@ -192,7 +192,7 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
 struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
 struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
-struct expr *expr_copy(struct expr *org);
+struct expr *expr_copy(const struct expr *org);
 void expr_free(struct expr *e);
 int expr_eq(struct expr *e1, struct expr *e2);
 void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
@@ -207,6 +207,7 @@ struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
 struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
 void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
 struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
 
 void expr_fprint(struct expr *e, FILE *out);
 struct gstr; /* forward */
index 3f7240df0f3b969f63956a06cf899091c47e70cb..febf0c94d5583b37a1411d601ab387998c4dc2d4 100644 (file)
@@ -14,6 +14,7 @@
 static inline const char *gettext(const char *txt) { return txt; }
 static inline void textdomain(const char *domainname) {}
 static inline void bindtextdomain(const char *name, const char *dir) {}
+static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
 #endif
 
 #ifdef __cplusplus
@@ -67,10 +68,12 @@ struct kconf_id {
        enum symbol_type stype;
 };
 
+#ifdef YYDEBUG
+extern int zconfdebug;
+#endif
+
 int zconfparse(void);
 void zconfdump(FILE *out);
-
-extern int zconfdebug;
 void zconf_starthelp(void);
 FILE *zconf_fopen(const char *name);
 void zconf_initscan(const char *name);
index 5f77dcb8977e0632b5875167d5a652ef62f4be1c..5fdf10dc1d8a45eb2ed06bffbb9425233b02c006 100644 (file)
@@ -203,7 +203,7 @@ void menu_add_option(int token, char *arg)
        }
 }
 
-static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
+static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
 {
        return sym2->type == S_INT || sym2->type == S_HEX ||
               (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
@@ -221,6 +221,15 @@ static void sym_check_prop(struct symbol *sym)
                                prop_warn(prop,
                                    "default for config symbol '%s'"
                                    " must be a single symbol", sym->name);
+                       if (prop->expr->type != E_SYMBOL)
+                               break;
+                       sym2 = prop_get_symbol(prop);
+                       if (sym->type == S_HEX || sym->type == S_INT) {
+                               if (!menu_validate_number(sym, sym2))
+                                       prop_warn(prop,
+                                           "'%s': number is invalid",
+                                           sym->name);
+                       }
                        break;
                case P_SELECT:
                        sym2 = prop_get_symbol(prop);
@@ -240,8 +249,8 @@ static void sym_check_prop(struct symbol *sym)
                        if (sym->type != S_INT && sym->type != S_HEX)
                                prop_warn(prop, "range is only allowed "
                                                "for int or hex symbols");
-                       if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
-                           !menu_range_valid_sym(sym, prop->expr->right.sym))
+                       if (!menu_validate_number(sym, prop->expr->left.sym) ||
+                           !menu_validate_number(sym, prop->expr->right.sym))
                                prop_warn(prop, "range is invalid");
                        break;
                default:
index 272a987f23e0bc56040c0931a363277395c511f1..db56377393d7922229562fa1ea767f3288424e25 100644 (file)
@@ -248,7 +248,7 @@ search_help[] = N_(
 "Only relevant lines are shown.\n"
 "\n\n"
 "Search examples:\n"
-"Examples: USB   = > find all symbols containing USB\n"
+"Examples: USB  => find all symbols containing USB\n"
 "          ^USB => find all symbols starting with USB\n"
 "          USB$ => find all symbols ending with USB\n"
 "\n");
@@ -1266,9 +1266,13 @@ static void conf_choice(struct menu *menu)
                        if (child->sym == sym_get_choice_value(menu->sym))
                                item_make(child, ':', "<X> %s",
                                                _(menu_get_prompt(child)));
-                       else
+                       else if (child->sym)
                                item_make(child, ':', "    %s",
                                                _(menu_get_prompt(child)));
+                       else
+                               item_make(child, ':', "*** %s ***",
+                                               _(menu_get_prompt(child)));
+
                        if (child->sym == active){
                                last_top_row = top_row(curses_menu);
                                selected_index = i;
@@ -1334,7 +1338,7 @@ static void conf_choice(struct menu *menu)
                        break;
 
                child = item_data();
-               if (!child || !menu_is_visible(child))
+               if (!child || !menu_is_visible(child) || !child->sym)
                        continue;
                switch (res) {
                case ' ':
index af6e9f3de9503b033a69a3eba7c2ecd212fef747..a796c95fe8a0eb460688cf7ab8201a6e77d4c794 100644 (file)
@@ -351,12 +351,16 @@ void sym_calc_value(struct symbol *sym)
                        }
                calc_newval:
                        if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
+                               struct expr *e;
+                               e = expr_simplify_unmet_dep(sym->rev_dep.expr,
+                                   sym->dir_dep.expr);
                                fprintf(stderr, "warning: (");
-                               expr_fprint(sym->rev_dep.expr, stderr);
+                               expr_fprint(e, stderr);
                                fprintf(stderr, ") selects %s which has unmet direct dependencies (",
                                        sym->name);
                                expr_fprint(sym->dir_dep.expr, stderr);
                                fprintf(stderr, ")\n");
+                               expr_free(e);
                        }
                        newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
                }
@@ -686,7 +690,7 @@ const char *sym_get_string_default(struct symbol *sym)
                switch (sym->type) {
                case S_BOOLEAN:
                case S_TRISTATE:
-                       /* The visibility imay limit the value from yes => mod */
+                       /* The visibility may limit the value from yes => mod */
                        val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
                        break;
                default:
index 2e3d3cd916b88be452585478ac71b771999903b1..446739c7843ab0f28b4efcead8574cd5ac5bb3ac 100755 (executable)
@@ -11,7 +11,7 @@ if [ -z "${MKIMAGE}" ]; then
        if [ -z "${MKIMAGE}" ]; then
                # Doesn't exist
                echo '"mkimage" command not found - U-Boot images will not be built' >&2
-               exit 0;
+               exit 1;
        fi
 fi
 
index 33122ca04e7cd99cfb1be6bb4a5c62fd66efe51b..97d2259ae999b6b7f99f709035b49b6e04e88480 100644 (file)
@@ -790,6 +790,7 @@ static const char *section_white_list[] =
 {
        ".comment*",
        ".debug*",
+       ".zdebug*",             /* Compressed debug sections. */
        ".GCC-command-line",    /* mn10300 */
        ".mdebug*",        /* alpha, score, mips etc. */
        ".pdr",            /* alpha, score, mips etc. */
@@ -1441,7 +1442,7 @@ static unsigned int *reloc_location(struct elf_info *elf,
        int section = shndx2secindex(sechdr->sh_info);
 
        return (void *)elf->hdr + sechdrs[section].sh_offset +
-               r->r_offset - sechdrs[section].sh_addr;
+               r->r_offset;
 }
 
 static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
index 49b74e1ee12d0b97f9e2ca5759e853b4917c1aad..b0b2357aef421ba9f63d608194ef4d052e540c30 100644 (file)
@@ -25,8 +25,44 @@ create_package() {
        chown -R root:root "$pdir"
        chmod -R go-w "$pdir"
 
+       # Attempt to find the correct Debian architecture
+       local forcearch="" debarch=""
+       case "$UTS_MACHINE" in
+       i386|ia64|alpha)
+               debarch="$UTS_MACHINE" ;;
+       x86_64)
+               debarch=amd64 ;;
+       sparc*)
+               debarch=sparc ;;
+       s390*)
+               debarch=s390 ;;
+       ppc*)
+               debarch=powerpc ;;
+       parisc*)
+               debarch=hppa ;;
+       mips*)
+               debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y .config && echo el) ;;
+       arm*)
+               debarch=arm$(grep -q CONFIG_AEABI=y .config && echo el) ;;
+       *)
+               echo "" >&2
+               echo "** ** **  WARNING  ** ** **" >&2
+               echo "" >&2
+               echo "Your architecture doesn't have it's equivalent" >&2
+               echo "Debian userspace architecture defined!" >&2
+               echo "Falling back to using your current userspace instead!" >&2
+               echo "Please add support for $UTS_MACHINE to ${0} ..." >&2
+               echo "" >&2
+       esac
+       if [ -n "$KBUILD_DEBARCH" ] ; then
+               debarch="$KBUILD_DEBARCH"
+       fi
+       if [ -n "$debarch" ] ; then
+               forcearch="-DArchitecture=$debarch"
+       fi
+
        # Create the package
-       dpkg-gencontrol -isp -p$pname -P"$pdir"
+       dpkg-gencontrol -isp $forcearch -p$pname -P"$pdir"
        dpkg --build "$pdir" ..
 }
 
@@ -40,17 +76,27 @@ else
 fi
 tmpdir="$objtree/debian/tmp"
 fwdir="$objtree/debian/fwtmp"
+kernel_headers_dir="$objtree/debian/hdrtmp"
+libc_headers_dir="$objtree/debian/headertmp"
 packagename=linux-image-$version
 fwpackagename=linux-firmware-image
+kernel_headers_packagename=linux-headers-$version
+libc_headers_packagename=linux-libc-dev
 
 if [ "$ARCH" = "um" ] ; then
        packagename=user-mode-linux-$version
 fi
 
 # Setup the directory structure
-rm -rf "$tmpdir" "$fwdir"
-mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename"
-mkdir -p "$fwdir/DEBIAN" "$fwdir/lib" "$fwdir/usr/share/doc/$fwpackagename"
+rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir"
+mkdir -m 755 -p "$tmpdir/DEBIAN"
+mkdir -p  "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename"
+mkdir -m 755 -p "$fwdir/DEBIAN"
+mkdir -p "$fwdir/lib" "$fwdir/usr/share/doc/$fwpackagename"
+mkdir -m 755 -p "$libc_headers_dir/DEBIAN"
+mkdir -p "$libc_headers_dir/usr/share/doc/$libc_headers_packagename"
+mkdir -m 755 -p "$kernel_headers_dir/DEBIAN"
+mkdir -p "$kernel_headers_dir/usr/share/doc/$kernel_headers_packagename"
 if [ "$ARCH" = "um" ] ; then
        mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin"
 fi
@@ -81,6 +127,9 @@ if grep -q '^CONFIG_MODULES=y' .config ; then
        fi
 fi
 
+make headers_check
+make headers_install INSTALL_HDR_PATH="$libc_headers_dir/usr"
+
 # Install the maintainer scripts
 # Note: hook scripts under /etc/kernel are also executed by official Debian
 # kernel packages, as well as kernel packages built using make-kpkg
@@ -188,6 +237,30 @@ EOF
 
 fi
 
+# Build header package
+find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$
+find arch/x86/include include scripts -type f >> /tmp/files$$
+(cd $objtree; find .config Module.symvers include scripts -type f >> /tmp/objfiles$$)
+destdir=$kernel_headers_dir/usr/src/linux-headers-$version
+mkdir -p "$destdir"
+tar -c -f - -T /tmp/files$$ | (cd $destdir; tar -xf -)
+(cd $objtree; tar -c -f - -T /tmp/objfiles$$) | (cd $destdir; tar -xf -)
+rm -f /tmp/files$$ /tmp/objfiles$$
+arch=$(dpkg --print-architecture)
+
+cat <<EOF >> debian/control
+
+Package: $kernel_headers_packagename
+Provides: linux-headers, linux-headers-2.6
+Architecture: $arch
+Description: Linux kernel headers for $KERNELRELEASE on $arch
+ This package provides kernel header files for $KERNELRELEASE on $arch
+ .
+ This is useful for people who need to build external modules
+EOF
+
+create_package "$kernel_headers_packagename" "$kernel_headers_dir"
+
 # Do we have firmware? Move it out of the way and build it into a package.
 if [ -e "$tmpdir/lib/firmware" ]; then
        mv "$tmpdir/lib/firmware" "$fwdir/lib/"
@@ -203,6 +276,18 @@ EOF
        create_package "$fwpackagename" "$fwdir"
 fi
 
+cat <<EOF >> debian/control
+
+Package: $libc_headers_packagename
+Section: devel
+Provides: linux-kernel-headers
+Architecture: any
+Description: Linux support headers for userspace development
+ This package provides userspaces headers from the Linux kernel.  These headers
+ are used by the installed headers for GNU glibc and other system libraries.
+EOF
+
+create_package "$libc_headers_packagename" "$libc_headers_dir"
 create_package "$packagename" "$tmpdir"
 
 exit 0
index bbbe584d44943077a41b22684b5ecdbce18f532a..92fdc4546141125a14410af0b8d4b1ce8464e2fe 100755 (executable)
@@ -123,7 +123,7 @@ exuberant()
        -I ____cacheline_internodealigned_in_smp                \
        -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL                      \
        -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \
-       --extra=+f --c-kinds=-px                                \
+       --extra=+f --c-kinds=+px                                \
        --regex-asm='/^ENTRY\(([^)]*)\).*/\1/'                  \
        --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \
        --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/'               \
index e80da955e6876aeb550bec75d3d99643020034eb..95accd442d55eeb5c81f6bcd39b63fc12e5a6f25 100644 (file)
@@ -21,6 +21,37 @@ config KEYS
 
          If you are unsure as to whether this is required, answer N.
 
+config TRUSTED_KEYS
+       tristate "TRUSTED KEYS"
+       depends on KEYS && TCG_TPM
+       select CRYPTO
+       select CRYPTO_HMAC
+       select CRYPTO_SHA1
+       help
+         This option provides support for creating, sealing, and unsealing
+         keys in the kernel. Trusted keys are random number symmetric keys,
+         generated and RSA-sealed by the TPM. The TPM only unseals the keys,
+         if the boot PCRs and other criteria match.  Userspace will only ever
+         see encrypted blobs.
+
+         If you are unsure as to whether this is required, answer N.
+
+config ENCRYPTED_KEYS
+       tristate "ENCRYPTED KEYS"
+       depends on KEYS && TRUSTED_KEYS
+       select CRYPTO_AES
+       select CRYPTO_CBC
+       select CRYPTO_SHA256
+       select CRYPTO_RNG
+       help
+         This option provides support for create/encrypting/decrypting keys
+         in the kernel.  Encrypted keys are kernel generated random numbers,
+         which are encrypted/decrypted with a 'master' symmetric key. The
+         'master' key can be either a trusted-key or user-key type.
+         Userspace only ever sees/stores encrypted blobs.
+
+         If you are unsure as to whether this is required, answer N.
+
 config KEYS_DEBUG_PROC_KEYS
        bool "Enable the /proc/keys file by which keys may be viewed"
        depends on KEYS
index be36feabb16a7234c1b314fdeed89facd46755d9..ab8c6d87f758716477757996bc2f2c998a1c8d3b 100644 (file)
 #ifndef __AA_FILE_H
 #define __AA_FILE_H
 
-#include <linux/path.h>
-
 #include "domain.h"
 #include "match.h"
 
 struct aa_profile;
+struct path;
 
 /*
  * We use MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND and the following flags
index 734a6d35112c4c9fc9278f456073ffe069c6e5a6..19ba16e8aacdb11fc02ba5fe3b6194455f4109af 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef __AA_MATCH_H
 #define __AA_MATCH_H
 
+#include <linux/kref.h>
 #include <linux/workqueue.h>
 
 #define DFA_NOMATCH                    0
index 74d5447d7df7259d83f54f5af5ff176fe4b5b37f..6c941050f5734d79354e657d0aec167d50923276 100644 (file)
@@ -13,6 +13,8 @@ obj-y := \
        request_key_auth.o \
        user_defined.o
 
+obj-$(CONFIG_TRUSTED_KEYS) += trusted_defined.o
+obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted_defined.o
 obj-$(CONFIG_KEYS_COMPAT) += compat.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/security/keys/encrypted_defined.c b/security/keys/encrypted_defined.c
new file mode 100644 (file)
index 0000000..32d27c8
--- /dev/null
@@ -0,0 +1,903 @@
+/*
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * Author:
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * See Documentation/keys-trusted-encrypted.txt
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/parser.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <keys/user-type.h>
+#include <keys/trusted-type.h>
+#include <keys/encrypted-type.h>
+#include <linux/key-type.h>
+#include <linux/random.h>
+#include <linux/rcupdate.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+#include <crypto/aes.h>
+
+#include "encrypted_defined.h"
+
+static const char KEY_TRUSTED_PREFIX[] = "trusted:";
+static const char KEY_USER_PREFIX[] = "user:";
+static const char hash_alg[] = "sha256";
+static const char hmac_alg[] = "hmac(sha256)";
+static const char blkcipher_alg[] = "cbc(aes)";
+static unsigned int ivsize;
+static int blksize;
+
+#define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
+#define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
+#define HASH_SIZE SHA256_DIGEST_SIZE
+#define MAX_DATA_SIZE 4096
+#define MIN_DATA_SIZE  20
+
+struct sdesc {
+       struct shash_desc shash;
+       char ctx[];
+};
+
+static struct crypto_shash *hashalg;
+static struct crypto_shash *hmacalg;
+
+enum {
+       Opt_err = -1, Opt_new, Opt_load, Opt_update
+};
+
+static const match_table_t key_tokens = {
+       {Opt_new, "new"},
+       {Opt_load, "load"},
+       {Opt_update, "update"},
+       {Opt_err, NULL}
+};
+
+static int aes_get_sizes(void)
+{
+       struct crypto_blkcipher *tfm;
+
+       tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm)) {
+               pr_err("encrypted_key: failed to alloc_cipher (%ld)\n",
+                      PTR_ERR(tfm));
+               return PTR_ERR(tfm);
+       }
+       ivsize = crypto_blkcipher_ivsize(tfm);
+       blksize = crypto_blkcipher_blocksize(tfm);
+       crypto_free_blkcipher(tfm);
+       return 0;
+}
+
+/*
+ * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key
+ *
+ * key-type:= "trusted:" | "encrypted:"
+ * desc:= master-key description
+ *
+ * Verify that 'key-type' is valid and that 'desc' exists. On key update,
+ * only the master key description is permitted to change, not the key-type.
+ * The key-type remains constant.
+ *
+ * On success returns 0, otherwise -EINVAL.
+ */
+static int valid_master_desc(const char *new_desc, const char *orig_desc)
+{
+       if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) {
+               if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN)
+                       goto out;
+               if (orig_desc)
+                       if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN))
+                               goto out;
+       } else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) {
+               if (strlen(new_desc) == KEY_USER_PREFIX_LEN)
+                       goto out;
+               if (orig_desc)
+                       if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN))
+                               goto out;
+       } else
+               goto out;
+       return 0;
+out:
+       return -EINVAL;
+}
+
+/*
+ * datablob_parse - parse the keyctl data
+ *
+ * datablob format:
+ * new <master-key name> <decrypted data length>
+ * load <master-key name> <decrypted data length> <encrypted iv + data>
+ * update <new-master-key name>
+ *
+ * Tokenizes a copy of the keyctl data, returning a pointer to each token,
+ * which is null terminated.
+ *
+ * On success returns 0, otherwise -EINVAL.
+ */
+static int datablob_parse(char *datablob, char **master_desc,
+                         char **decrypted_datalen, char **hex_encoded_iv)
+{
+       substring_t args[MAX_OPT_ARGS];
+       int ret = -EINVAL;
+       int key_cmd;
+       char *p;
+
+       p = strsep(&datablob, " \t");
+       if (!p)
+               return ret;
+       key_cmd = match_token(p, key_tokens, args);
+
+       *master_desc = strsep(&datablob, " \t");
+       if (!*master_desc)
+               goto out;
+
+       if (valid_master_desc(*master_desc, NULL) < 0)
+               goto out;
+
+       if (decrypted_datalen) {
+               *decrypted_datalen = strsep(&datablob, " \t");
+               if (!*decrypted_datalen)
+                       goto out;
+       }
+
+       switch (key_cmd) {
+       case Opt_new:
+               if (!decrypted_datalen)
+                       break;
+               ret = 0;
+               break;
+       case Opt_load:
+               if (!decrypted_datalen)
+                       break;
+               *hex_encoded_iv = strsep(&datablob, " \t");
+               if (!*hex_encoded_iv)
+                       break;
+               ret = 0;
+               break;
+       case Opt_update:
+               if (decrypted_datalen)
+                       break;
+               ret = 0;
+               break;
+       case Opt_err:
+               break;
+       }
+out:
+       return ret;
+}
+
+/*
+ * datablob_format - format as an ascii string, before copying to userspace
+ */
+static char *datablob_format(struct encrypted_key_payload *epayload,
+                            size_t asciiblob_len)
+{
+       char *ascii_buf, *bufp;
+       u8 *iv = epayload->iv;
+       int len;
+       int i;
+
+       ascii_buf = kmalloc(asciiblob_len + 1, GFP_KERNEL);
+       if (!ascii_buf)
+               goto out;
+
+       ascii_buf[asciiblob_len] = '\0';
+
+       /* copy datablob master_desc and datalen strings */
+       len = sprintf(ascii_buf, "%s %s ", epayload->master_desc,
+                     epayload->datalen);
+
+       /* convert the hex encoded iv, encrypted-data and HMAC to ascii */
+       bufp = &ascii_buf[len];
+       for (i = 0; i < (asciiblob_len - len) / 2; i++)
+               bufp = pack_hex_byte(bufp, iv[i]);
+out:
+       return ascii_buf;
+}
+
+/*
+ * request_trusted_key - request the trusted key
+ *
+ * Trusted keys are sealed to PCRs and other metadata. Although userspace
+ * manages both trusted/encrypted key-types, like the encrypted key type
+ * data, trusted key type data is not visible decrypted from userspace.
+ */
+static struct key *request_trusted_key(const char *trusted_desc,
+                                      u8 **master_key, size_t *master_keylen)
+{
+       struct trusted_key_payload *tpayload;
+       struct key *tkey;
+
+       tkey = request_key(&key_type_trusted, trusted_desc, NULL);
+       if (IS_ERR(tkey))
+               goto error;
+
+       down_read(&tkey->sem);
+       tpayload = rcu_dereference(tkey->payload.data);
+       *master_key = tpayload->key;
+       *master_keylen = tpayload->key_len;
+error:
+       return tkey;
+}
+
+/*
+ * request_user_key - request the user key
+ *
+ * Use a user provided key to encrypt/decrypt an encrypted-key.
+ */
+static struct key *request_user_key(const char *master_desc, u8 **master_key,
+                                   size_t *master_keylen)
+{
+       struct user_key_payload *upayload;
+       struct key *ukey;
+
+       ukey = request_key(&key_type_user, master_desc, NULL);
+       if (IS_ERR(ukey))
+               goto error;
+
+       down_read(&ukey->sem);
+       upayload = rcu_dereference(ukey->payload.data);
+       *master_key = upayload->data;
+       *master_keylen = upayload->datalen;
+error:
+       return ukey;
+}
+
+static struct sdesc *alloc_sdesc(struct crypto_shash *alg)
+{
+       struct sdesc *sdesc;
+       int size;
+
+       size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
+       sdesc = kmalloc(size, GFP_KERNEL);
+       if (!sdesc)
+               return ERR_PTR(-ENOMEM);
+       sdesc->shash.tfm = alg;
+       sdesc->shash.flags = 0x0;
+       return sdesc;
+}
+
+static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen,
+                    const u8 *buf, unsigned int buflen)
+{
+       struct sdesc *sdesc;
+       int ret;
+
+       sdesc = alloc_sdesc(hmacalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("encrypted_key: can't alloc %s\n", hmac_alg);
+               return PTR_ERR(sdesc);
+       }
+
+       ret = crypto_shash_setkey(hmacalg, key, keylen);
+       if (!ret)
+               ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
+       kfree(sdesc);
+       return ret;
+}
+
+static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen)
+{
+       struct sdesc *sdesc;
+       int ret;
+
+       sdesc = alloc_sdesc(hashalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("encrypted_key: can't alloc %s\n", hash_alg);
+               return PTR_ERR(sdesc);
+       }
+
+       ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
+       kfree(sdesc);
+       return ret;
+}
+
+enum derived_key_type { ENC_KEY, AUTH_KEY };
+
+/* Derive authentication/encryption key from trusted key */
+static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
+                          const u8 *master_key, size_t master_keylen)
+{
+       u8 *derived_buf;
+       unsigned int derived_buf_len;
+       int ret;
+
+       derived_buf_len = strlen("AUTH_KEY") + 1 + master_keylen;
+       if (derived_buf_len < HASH_SIZE)
+               derived_buf_len = HASH_SIZE;
+
+       derived_buf = kzalloc(derived_buf_len, GFP_KERNEL);
+       if (!derived_buf) {
+               pr_err("encrypted_key: out of memory\n");
+               return -ENOMEM;
+       }
+       if (key_type)
+               strcpy(derived_buf, "AUTH_KEY");
+       else
+               strcpy(derived_buf, "ENC_KEY");
+
+       memcpy(derived_buf + strlen(derived_buf) + 1, master_key,
+              master_keylen);
+       ret = calc_hash(derived_key, derived_buf, derived_buf_len);
+       kfree(derived_buf);
+       return ret;
+}
+
+static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key,
+                              unsigned int key_len, const u8 *iv,
+                              unsigned int ivsize)
+{
+       int ret;
+
+       desc->tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(desc->tfm)) {
+               pr_err("encrypted_key: failed to load %s transform (%ld)\n",
+                      blkcipher_alg, PTR_ERR(desc->tfm));
+               return PTR_ERR(desc->tfm);
+       }
+       desc->flags = 0;
+
+       ret = crypto_blkcipher_setkey(desc->tfm, key, key_len);
+       if (ret < 0) {
+               pr_err("encrypted_key: failed to setkey (%d)\n", ret);
+               crypto_free_blkcipher(desc->tfm);
+               return ret;
+       }
+       crypto_blkcipher_set_iv(desc->tfm, iv, ivsize);
+       return 0;
+}
+
+static struct key *request_master_key(struct encrypted_key_payload *epayload,
+                                     u8 **master_key, size_t *master_keylen)
+{
+       struct key *mkey = NULL;
+
+       if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX,
+                    KEY_TRUSTED_PREFIX_LEN)) {
+               mkey = request_trusted_key(epayload->master_desc +
+                                          KEY_TRUSTED_PREFIX_LEN,
+                                          master_key, master_keylen);
+       } else if (!strncmp(epayload->master_desc, KEY_USER_PREFIX,
+                           KEY_USER_PREFIX_LEN)) {
+               mkey = request_user_key(epayload->master_desc +
+                                       KEY_USER_PREFIX_LEN,
+                                       master_key, master_keylen);
+       } else
+               goto out;
+
+       if (IS_ERR(mkey))
+               pr_info("encrypted_key: key %s not found",
+                       epayload->master_desc);
+       if (mkey)
+               dump_master_key(*master_key, *master_keylen);
+out:
+       return mkey;
+}
+
+/* Before returning data to userspace, encrypt decrypted data. */
+static int derived_key_encrypt(struct encrypted_key_payload *epayload,
+                              const u8 *derived_key,
+                              unsigned int derived_keylen)
+{
+       struct scatterlist sg_in[2];
+       struct scatterlist sg_out[1];
+       struct blkcipher_desc desc;
+       unsigned int encrypted_datalen;
+       unsigned int padlen;
+       char pad[16];
+       int ret;
+
+       encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
+       padlen = encrypted_datalen - epayload->decrypted_datalen;
+
+       ret = init_blkcipher_desc(&desc, derived_key, derived_keylen,
+                                 epayload->iv, ivsize);
+       if (ret < 0)
+               goto out;
+       dump_decrypted_data(epayload);
+
+       memset(pad, 0, sizeof pad);
+       sg_init_table(sg_in, 2);
+       sg_set_buf(&sg_in[0], epayload->decrypted_data,
+                  epayload->decrypted_datalen);
+       sg_set_buf(&sg_in[1], pad, padlen);
+
+       sg_init_table(sg_out, 1);
+       sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen);
+
+       ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen);
+       crypto_free_blkcipher(desc.tfm);
+       if (ret < 0)
+               pr_err("encrypted_key: failed to encrypt (%d)\n", ret);
+       else
+               dump_encrypted_data(epayload, encrypted_datalen);
+out:
+       return ret;
+}
+
+static int datablob_hmac_append(struct encrypted_key_payload *epayload,
+                               const u8 *master_key, size_t master_keylen)
+{
+       u8 derived_key[HASH_SIZE];
+       u8 *digest;
+       int ret;
+
+       ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
+       if (ret < 0)
+               goto out;
+
+       digest = epayload->master_desc + epayload->datablob_len;
+       ret = calc_hmac(digest, derived_key, sizeof derived_key,
+                       epayload->master_desc, epayload->datablob_len);
+       if (!ret)
+               dump_hmac(NULL, digest, HASH_SIZE);
+out:
+       return ret;
+}
+
+/* verify HMAC before decrypting encrypted key */
+static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
+                               const u8 *master_key, size_t master_keylen)
+{
+       u8 derived_key[HASH_SIZE];
+       u8 digest[HASH_SIZE];
+       int ret;
+
+       ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
+       if (ret < 0)
+               goto out;
+
+       ret = calc_hmac(digest, derived_key, sizeof derived_key,
+                       epayload->master_desc, epayload->datablob_len);
+       if (ret < 0)
+               goto out;
+       ret = memcmp(digest, epayload->master_desc + epayload->datablob_len,
+                    sizeof digest);
+       if (ret) {
+               ret = -EINVAL;
+               dump_hmac("datablob",
+                         epayload->master_desc + epayload->datablob_len,
+                         HASH_SIZE);
+               dump_hmac("calc", digest, HASH_SIZE);
+       }
+out:
+       return ret;
+}
+
+static int derived_key_decrypt(struct encrypted_key_payload *epayload,
+                              const u8 *derived_key,
+                              unsigned int derived_keylen)
+{
+       struct scatterlist sg_in[1];
+       struct scatterlist sg_out[2];
+       struct blkcipher_desc desc;
+       unsigned int encrypted_datalen;
+       char pad[16];
+       int ret;
+
+       encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
+       ret = init_blkcipher_desc(&desc, derived_key, derived_keylen,
+                                 epayload->iv, ivsize);
+       if (ret < 0)
+               goto out;
+       dump_encrypted_data(epayload, encrypted_datalen);
+
+       memset(pad, 0, sizeof pad);
+       sg_init_table(sg_in, 1);
+       sg_init_table(sg_out, 2);
+       sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen);
+       sg_set_buf(&sg_out[0], epayload->decrypted_data,
+                  epayload->decrypted_datalen);
+       sg_set_buf(&sg_out[1], pad, sizeof pad);
+
+       ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, encrypted_datalen);
+       crypto_free_blkcipher(desc.tfm);
+       if (ret < 0)
+               goto out;
+       dump_decrypted_data(epayload);
+out:
+       return ret;
+}
+
+/* Allocate memory for decrypted key and datablob. */
+static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
+                                                        const char *master_desc,
+                                                        const char *datalen)
+{
+       struct encrypted_key_payload *epayload = NULL;
+       unsigned short datablob_len;
+       unsigned short decrypted_datalen;
+       unsigned int encrypted_datalen;
+       long dlen;
+       int ret;
+
+       ret = strict_strtol(datalen, 10, &dlen);
+       if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE)
+               return ERR_PTR(-EINVAL);
+
+       decrypted_datalen = dlen;
+       encrypted_datalen = roundup(decrypted_datalen, blksize);
+
+       datablob_len = strlen(master_desc) + 1 + strlen(datalen) + 1
+           + ivsize + 1 + encrypted_datalen;
+
+       ret = key_payload_reserve(key, decrypted_datalen + datablob_len
+                                 + HASH_SIZE + 1);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       epayload = kzalloc(sizeof(*epayload) + decrypted_datalen +
+                          datablob_len + HASH_SIZE + 1, GFP_KERNEL);
+       if (!epayload)
+               return ERR_PTR(-ENOMEM);
+
+       epayload->decrypted_datalen = decrypted_datalen;
+       epayload->datablob_len = datablob_len;
+       return epayload;
+}
+
+static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
+                                const char *hex_encoded_iv)
+{
+       struct key *mkey;
+       u8 derived_key[HASH_SIZE];
+       u8 *master_key;
+       u8 *hmac;
+       const char *hex_encoded_data;
+       unsigned int encrypted_datalen;
+       size_t master_keylen;
+       size_t asciilen;
+       int ret;
+
+       encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
+       asciilen = (ivsize + 1 + encrypted_datalen + HASH_SIZE) * 2;
+       if (strlen(hex_encoded_iv) != asciilen)
+               return -EINVAL;
+
+       hex_encoded_data = hex_encoded_iv + (2 * ivsize) + 2;
+       hex2bin(epayload->iv, hex_encoded_iv, ivsize);
+       hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen);
+
+       hmac = epayload->master_desc + epayload->datablob_len;
+       hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE);
+
+       mkey = request_master_key(epayload, &master_key, &master_keylen);
+       if (IS_ERR(mkey))
+               return PTR_ERR(mkey);
+
+       ret = datablob_hmac_verify(epayload, master_key, master_keylen);
+       if (ret < 0) {
+               pr_err("encrypted_key: bad hmac (%d)\n", ret);
+               goto out;
+       }
+
+       ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
+       if (ret < 0)
+               goto out;
+
+       ret = derived_key_decrypt(epayload, derived_key, sizeof derived_key);
+       if (ret < 0)
+               pr_err("encrypted_key: failed to decrypt key (%d)\n", ret);
+out:
+       up_read(&mkey->sem);
+       key_put(mkey);
+       return ret;
+}
+
+static void __ekey_init(struct encrypted_key_payload *epayload,
+                       const char *master_desc, const char *datalen)
+{
+       epayload->master_desc = epayload->decrypted_data
+           + epayload->decrypted_datalen;
+       epayload->datalen = epayload->master_desc + strlen(master_desc) + 1;
+       epayload->iv = epayload->datalen + strlen(datalen) + 1;
+       epayload->encrypted_data = epayload->iv + ivsize + 1;
+
+       memcpy(epayload->master_desc, master_desc, strlen(master_desc));
+       memcpy(epayload->datalen, datalen, strlen(datalen));
+}
+
+/*
+ * encrypted_init - initialize an encrypted key
+ *
+ * For a new key, use a random number for both the iv and data
+ * itself.  For an old key, decrypt the hex encoded data.
+ */
+static int encrypted_init(struct encrypted_key_payload *epayload,
+                         const char *master_desc, const char *datalen,
+                         const char *hex_encoded_iv)
+{
+       int ret = 0;
+
+       __ekey_init(epayload, master_desc, datalen);
+       if (!hex_encoded_iv) {
+               get_random_bytes(epayload->iv, ivsize);
+
+               get_random_bytes(epayload->decrypted_data,
+                                epayload->decrypted_datalen);
+       } else
+               ret = encrypted_key_decrypt(epayload, hex_encoded_iv);
+       return ret;
+}
+
+/*
+ * encrypted_instantiate - instantiate an encrypted key
+ *
+ * Decrypt an existing encrypted datablob or create a new encrypted key
+ * based on a kernel random number.
+ *
+ * On success, return 0. Otherwise return errno.
+ */
+static int encrypted_instantiate(struct key *key, const void *data,
+                                size_t datalen)
+{
+       struct encrypted_key_payload *epayload = NULL;
+       char *datablob = NULL;
+       char *master_desc = NULL;
+       char *decrypted_datalen = NULL;
+       char *hex_encoded_iv = NULL;
+       int ret;
+
+       if (datalen <= 0 || datalen > 32767 || !data)
+               return -EINVAL;
+
+       datablob = kmalloc(datalen + 1, GFP_KERNEL);
+       if (!datablob)
+               return -ENOMEM;
+       datablob[datalen] = 0;
+       memcpy(datablob, data, datalen);
+       ret = datablob_parse(datablob, &master_desc, &decrypted_datalen,
+                            &hex_encoded_iv);
+       if (ret < 0)
+               goto out;
+
+       epayload = encrypted_key_alloc(key, master_desc, decrypted_datalen);
+       if (IS_ERR(epayload)) {
+               ret = PTR_ERR(epayload);
+               goto out;
+       }
+       ret = encrypted_init(epayload, master_desc, decrypted_datalen,
+                            hex_encoded_iv);
+       if (ret < 0) {
+               kfree(epayload);
+               goto out;
+       }
+
+       rcu_assign_pointer(key->payload.data, epayload);
+out:
+       kfree(datablob);
+       return ret;
+}
+
+static void encrypted_rcu_free(struct rcu_head *rcu)
+{
+       struct encrypted_key_payload *epayload;
+
+       epayload = container_of(rcu, struct encrypted_key_payload, rcu);
+       memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
+       kfree(epayload);
+}
+
+/*
+ * encrypted_update - update the master key description
+ *
+ * Change the master key description for an existing encrypted key.
+ * The next read will return an encrypted datablob using the new
+ * master key description.
+ *
+ * On success, return 0. Otherwise return errno.
+ */
+static int encrypted_update(struct key *key, const void *data, size_t datalen)
+{
+       struct encrypted_key_payload *epayload = key->payload.data;
+       struct encrypted_key_payload *new_epayload;
+       char *buf;
+       char *new_master_desc = NULL;
+       int ret = 0;
+
+       if (datalen <= 0 || datalen > 32767 || !data)
+               return -EINVAL;
+
+       buf = kmalloc(datalen + 1, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf[datalen] = 0;
+       memcpy(buf, data, datalen);
+       ret = datablob_parse(buf, &new_master_desc, NULL, NULL);
+       if (ret < 0)
+               goto out;
+
+       ret = valid_master_desc(new_master_desc, epayload->master_desc);
+       if (ret < 0)
+               goto out;
+
+       new_epayload = encrypted_key_alloc(key, new_master_desc,
+                                          epayload->datalen);
+       if (IS_ERR(new_epayload)) {
+               ret = PTR_ERR(new_epayload);
+               goto out;
+       }
+
+       __ekey_init(new_epayload, new_master_desc, epayload->datalen);
+
+       memcpy(new_epayload->iv, epayload->iv, ivsize);
+       memcpy(new_epayload->decrypted_data, epayload->decrypted_data,
+              epayload->decrypted_datalen);
+
+       rcu_assign_pointer(key->payload.data, new_epayload);
+       call_rcu(&epayload->rcu, encrypted_rcu_free);
+out:
+       kfree(buf);
+       return ret;
+}
+
+/*
+ * encrypted_read - format and copy the encrypted data to userspace
+ *
+ * The resulting datablob format is:
+ * <master-key name> <decrypted data length> <encrypted iv> <encrypted data>
+ *
+ * On success, return to userspace the encrypted key datablob size.
+ */
+static long encrypted_read(const struct key *key, char __user *buffer,
+                          size_t buflen)
+{
+       struct encrypted_key_payload *epayload;
+       struct key *mkey;
+       u8 *master_key;
+       size_t master_keylen;
+       char derived_key[HASH_SIZE];
+       char *ascii_buf;
+       size_t asciiblob_len;
+       int ret;
+
+       epayload = rcu_dereference_protected(key->payload.data,
+                                 rwsem_is_locked(&((struct key *)key)->sem));
+
+       /* returns the hex encoded iv, encrypted-data, and hmac as ascii */
+       asciiblob_len = epayload->datablob_len + ivsize + 1
+           + roundup(epayload->decrypted_datalen, blksize)
+           + (HASH_SIZE * 2);
+
+       if (!buffer || buflen < asciiblob_len)
+               return asciiblob_len;
+
+       mkey = request_master_key(epayload, &master_key, &master_keylen);
+       if (IS_ERR(mkey))
+               return PTR_ERR(mkey);
+
+       ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
+       if (ret < 0)
+               goto out;
+
+       ret = derived_key_encrypt(epayload, derived_key, sizeof derived_key);
+       if (ret < 0)
+               goto out;
+
+       ret = datablob_hmac_append(epayload, master_key, master_keylen);
+       if (ret < 0)
+               goto out;
+
+       ascii_buf = datablob_format(epayload, asciiblob_len);
+       if (!ascii_buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       up_read(&mkey->sem);
+       key_put(mkey);
+
+       if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0)
+               ret = -EFAULT;
+       kfree(ascii_buf);
+
+       return asciiblob_len;
+out:
+       up_read(&mkey->sem);
+       key_put(mkey);
+       return ret;
+}
+
+/*
+ * encrypted_destroy - before freeing the key, clear the decrypted data
+ *
+ * Before freeing the key, clear the memory containing the decrypted
+ * key data.
+ */
+static void encrypted_destroy(struct key *key)
+{
+       struct encrypted_key_payload *epayload = key->payload.data;
+
+       if (!epayload)
+               return;
+
+       memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
+       kfree(key->payload.data);
+}
+
+struct key_type key_type_encrypted = {
+       .name = "encrypted",
+       .instantiate = encrypted_instantiate,
+       .update = encrypted_update,
+       .match = user_match,
+       .destroy = encrypted_destroy,
+       .describe = user_describe,
+       .read = encrypted_read,
+};
+EXPORT_SYMBOL_GPL(key_type_encrypted);
+
+static void encrypted_shash_release(void)
+{
+       if (hashalg)
+               crypto_free_shash(hashalg);
+       if (hmacalg)
+               crypto_free_shash(hmacalg);
+}
+
+static int __init encrypted_shash_alloc(void)
+{
+       int ret;
+
+       hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(hmacalg)) {
+               pr_info("encrypted_key: could not allocate crypto %s\n",
+                       hmac_alg);
+               return PTR_ERR(hmacalg);
+       }
+
+       hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(hashalg)) {
+               pr_info("encrypted_key: could not allocate crypto %s\n",
+                       hash_alg);
+               ret = PTR_ERR(hashalg);
+               goto hashalg_fail;
+       }
+
+       return 0;
+
+hashalg_fail:
+       crypto_free_shash(hmacalg);
+       return ret;
+}
+
+static int __init init_encrypted(void)
+{
+       int ret;
+
+       ret = encrypted_shash_alloc();
+       if (ret < 0)
+               return ret;
+       ret = register_key_type(&key_type_encrypted);
+       if (ret < 0)
+               goto out;
+       return aes_get_sizes();
+out:
+       encrypted_shash_release();
+       return ret;
+
+}
+
+static void __exit cleanup_encrypted(void)
+{
+       encrypted_shash_release();
+       unregister_key_type(&key_type_encrypted);
+}
+
+late_initcall(init_encrypted);
+module_exit(cleanup_encrypted);
+
+MODULE_LICENSE("GPL");
diff --git a/security/keys/encrypted_defined.h b/security/keys/encrypted_defined.h
new file mode 100644 (file)
index 0000000..cef5e2f
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __ENCRYPTED_KEY_H
+#define __ENCRYPTED_KEY_H
+
+#define ENCRYPTED_DEBUG 0
+
+#if ENCRYPTED_DEBUG
+static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
+{
+       print_hex_dump(KERN_ERR, "master key: ", DUMP_PREFIX_NONE, 32, 1,
+                      master_key, master_keylen, 0);
+}
+
+static inline void dump_decrypted_data(struct encrypted_key_payload *epayload)
+{
+       print_hex_dump(KERN_ERR, "decrypted data: ", DUMP_PREFIX_NONE, 32, 1,
+                      epayload->decrypted_data,
+                      epayload->decrypted_datalen, 0);
+}
+
+static inline void dump_encrypted_data(struct encrypted_key_payload *epayload,
+                                      unsigned int encrypted_datalen)
+{
+       print_hex_dump(KERN_ERR, "encrypted data: ", DUMP_PREFIX_NONE, 32, 1,
+                      epayload->encrypted_data, encrypted_datalen, 0);
+}
+
+static inline void dump_hmac(const char *str, const u8 *digest,
+                            unsigned int hmac_size)
+{
+       if (str)
+               pr_info("encrypted_key: %s", str);
+       print_hex_dump(KERN_ERR, "hmac: ", DUMP_PREFIX_NONE, 32, 1, digest,
+                      hmac_size, 0);
+}
+#else
+static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
+{
+}
+
+static inline void dump_decrypted_data(struct encrypted_key_payload *epayload)
+{
+}
+
+static inline void dump_encrypted_data(struct encrypted_key_payload *epayload,
+                                      unsigned int encrypted_datalen)
+{
+}
+
+static inline void dump_hmac(const char *str, const u8 *digest,
+                            unsigned int hmac_size)
+{
+}
+#endif
+#endif
diff --git a/security/keys/trusted_defined.c b/security/keys/trusted_defined.c
new file mode 100644 (file)
index 0000000..975e9f2
--- /dev/null
@@ -0,0 +1,1175 @@
+/*
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * Author:
+ * David Safford <safford@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * See Documentation/keys-trusted-encrypted.txt
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/parser.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <keys/user-type.h>
+#include <keys/trusted-type.h>
+#include <linux/key-type.h>
+#include <linux/rcupdate.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+#include <linux/capability.h>
+#include <linux/tpm.h>
+#include <linux/tpm_command.h>
+
+#include "trusted_defined.h"
+
+static const char hmac_alg[] = "hmac(sha1)";
+static const char hash_alg[] = "sha1";
+
+struct sdesc {
+       struct shash_desc shash;
+       char ctx[];
+};
+
+static struct crypto_shash *hashalg;
+static struct crypto_shash *hmacalg;
+
+static struct sdesc *init_sdesc(struct crypto_shash *alg)
+{
+       struct sdesc *sdesc;
+       int size;
+
+       size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
+       sdesc = kmalloc(size, GFP_KERNEL);
+       if (!sdesc)
+               return ERR_PTR(-ENOMEM);
+       sdesc->shash.tfm = alg;
+       sdesc->shash.flags = 0x0;
+       return sdesc;
+}
+
+static int TSS_sha1(const unsigned char *data, unsigned int datalen,
+                   unsigned char *digest)
+{
+       struct sdesc *sdesc;
+       int ret;
+
+       sdesc = init_sdesc(hashalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("trusted_key: can't alloc %s\n", hash_alg);
+               return PTR_ERR(sdesc);
+       }
+
+       ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
+       kfree(sdesc);
+       return ret;
+}
+
+static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
+                      unsigned int keylen, ...)
+{
+       struct sdesc *sdesc;
+       va_list argp;
+       unsigned int dlen;
+       unsigned char *data;
+       int ret;
+
+       sdesc = init_sdesc(hmacalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("trusted_key: can't alloc %s\n", hmac_alg);
+               return PTR_ERR(sdesc);
+       }
+
+       ret = crypto_shash_setkey(hmacalg, key, keylen);
+       if (ret < 0)
+               goto out;
+       ret = crypto_shash_init(&sdesc->shash);
+       if (ret < 0)
+               goto out;
+
+       va_start(argp, keylen);
+       for (;;) {
+               dlen = va_arg(argp, unsigned int);
+               if (dlen == 0)
+                       break;
+               data = va_arg(argp, unsigned char *);
+               if (data == NULL)
+                       return -EINVAL;
+               ret = crypto_shash_update(&sdesc->shash, data, dlen);
+               if (ret < 0)
+                       goto out;
+       }
+       va_end(argp);
+       if (!ret)
+               ret = crypto_shash_final(&sdesc->shash, digest);
+out:
+       kfree(sdesc);
+       return ret;
+}
+
+/*
+ * calculate authorization info fields to send to TPM
+ */
+static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
+                       unsigned int keylen, unsigned char *h1,
+                       unsigned char *h2, unsigned char h3, ...)
+{
+       unsigned char paramdigest[SHA1_DIGEST_SIZE];
+       struct sdesc *sdesc;
+       unsigned int dlen;
+       unsigned char *data;
+       unsigned char c;
+       int ret;
+       va_list argp;
+
+       sdesc = init_sdesc(hashalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("trusted_key: can't alloc %s\n", hash_alg);
+               return PTR_ERR(sdesc);
+       }
+
+       c = h3;
+       ret = crypto_shash_init(&sdesc->shash);
+       if (ret < 0)
+               goto out;
+       va_start(argp, h3);
+       for (;;) {
+               dlen = va_arg(argp, unsigned int);
+               if (dlen == 0)
+                       break;
+               data = va_arg(argp, unsigned char *);
+               ret = crypto_shash_update(&sdesc->shash, data, dlen);
+               if (ret < 0) {
+                       va_end(argp);
+                       goto out;
+               }
+       }
+       va_end(argp);
+       ret = crypto_shash_final(&sdesc->shash, paramdigest);
+       if (!ret)
+               ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
+                                 paramdigest, TPM_NONCE_SIZE, h1,
+                                 TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
+out:
+       kfree(sdesc);
+       return ret;
+}
+
+/*
+ * verify the AUTH1_COMMAND (Seal) result from TPM
+ */
+static int TSS_checkhmac1(unsigned char *buffer,
+                         const uint32_t command,
+                         const unsigned char *ononce,
+                         const unsigned char *key,
+                         unsigned int keylen, ...)
+{
+       uint32_t bufsize;
+       uint16_t tag;
+       uint32_t ordinal;
+       uint32_t result;
+       unsigned char *enonce;
+       unsigned char *continueflag;
+       unsigned char *authdata;
+       unsigned char testhmac[SHA1_DIGEST_SIZE];
+       unsigned char paramdigest[SHA1_DIGEST_SIZE];
+       struct sdesc *sdesc;
+       unsigned int dlen;
+       unsigned int dpos;
+       va_list argp;
+       int ret;
+
+       bufsize = LOAD32(buffer, TPM_SIZE_OFFSET);
+       tag = LOAD16(buffer, 0);
+       ordinal = command;
+       result = LOAD32N(buffer, TPM_RETURN_OFFSET);
+       if (tag == TPM_TAG_RSP_COMMAND)
+               return 0;
+       if (tag != TPM_TAG_RSP_AUTH1_COMMAND)
+               return -EINVAL;
+       authdata = buffer + bufsize - SHA1_DIGEST_SIZE;
+       continueflag = authdata - 1;
+       enonce = continueflag - TPM_NONCE_SIZE;
+
+       sdesc = init_sdesc(hashalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("trusted_key: can't alloc %s\n", hash_alg);
+               return PTR_ERR(sdesc);
+       }
+       ret = crypto_shash_init(&sdesc->shash);
+       if (ret < 0)
+               goto out;
+       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result,
+                                 sizeof result);
+       if (ret < 0)
+               goto out;
+       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal,
+                                 sizeof ordinal);
+       if (ret < 0)
+               goto out;
+       va_start(argp, keylen);
+       for (;;) {
+               dlen = va_arg(argp, unsigned int);
+               if (dlen == 0)
+                       break;
+               dpos = va_arg(argp, unsigned int);
+               ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
+               if (ret < 0) {
+                       va_end(argp);
+                       goto out;
+               }
+       }
+       va_end(argp);
+       ret = crypto_shash_final(&sdesc->shash, paramdigest);
+       if (ret < 0)
+               goto out;
+
+       ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest,
+                         TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce,
+                         1, continueflag, 0, 0);
+       if (ret < 0)
+               goto out;
+
+       if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
+               ret = -EINVAL;
+out:
+       kfree(sdesc);
+       return ret;
+}
+
+/*
+ * verify the AUTH2_COMMAND (unseal) result from TPM
+ */
+static int TSS_checkhmac2(unsigned char *buffer,
+                         const uint32_t command,
+                         const unsigned char *ononce,
+                         const unsigned char *key1,
+                         unsigned int keylen1,
+                         const unsigned char *key2,
+                         unsigned int keylen2, ...)
+{
+       uint32_t bufsize;
+       uint16_t tag;
+       uint32_t ordinal;
+       uint32_t result;
+       unsigned char *enonce1;
+       unsigned char *continueflag1;
+       unsigned char *authdata1;
+       unsigned char *enonce2;
+       unsigned char *continueflag2;
+       unsigned char *authdata2;
+       unsigned char testhmac1[SHA1_DIGEST_SIZE];
+       unsigned char testhmac2[SHA1_DIGEST_SIZE];
+       unsigned char paramdigest[SHA1_DIGEST_SIZE];
+       struct sdesc *sdesc;
+       unsigned int dlen;
+       unsigned int dpos;
+       va_list argp;
+       int ret;
+
+       bufsize = LOAD32(buffer, TPM_SIZE_OFFSET);
+       tag = LOAD16(buffer, 0);
+       ordinal = command;
+       result = LOAD32N(buffer, TPM_RETURN_OFFSET);
+
+       if (tag == TPM_TAG_RSP_COMMAND)
+               return 0;
+       if (tag != TPM_TAG_RSP_AUTH2_COMMAND)
+               return -EINVAL;
+       authdata1 = buffer + bufsize - (SHA1_DIGEST_SIZE + 1
+                       + SHA1_DIGEST_SIZE + SHA1_DIGEST_SIZE);
+       authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE);
+       continueflag1 = authdata1 - 1;
+       continueflag2 = authdata2 - 1;
+       enonce1 = continueflag1 - TPM_NONCE_SIZE;
+       enonce2 = continueflag2 - TPM_NONCE_SIZE;
+
+       sdesc = init_sdesc(hashalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("trusted_key: can't alloc %s\n", hash_alg);
+               return PTR_ERR(sdesc);
+       }
+       ret = crypto_shash_init(&sdesc->shash);
+       if (ret < 0)
+               goto out;
+       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result,
+                                 sizeof result);
+       if (ret < 0)
+               goto out;
+       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal,
+                                 sizeof ordinal);
+       if (ret < 0)
+               goto out;
+
+       va_start(argp, keylen2);
+       for (;;) {
+               dlen = va_arg(argp, unsigned int);
+               if (dlen == 0)
+                       break;
+               dpos = va_arg(argp, unsigned int);
+               ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
+               if (ret < 0) {
+                       va_end(argp);
+                       goto out;
+               }
+       }
+       va_end(argp);
+       ret = crypto_shash_final(&sdesc->shash, paramdigest);
+       if (ret < 0)
+               goto out;
+
+       ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE,
+                         paramdigest, TPM_NONCE_SIZE, enonce1,
+                         TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0);
+       if (ret < 0)
+               goto out;
+       if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) {
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE,
+                         paramdigest, TPM_NONCE_SIZE, enonce2,
+                         TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0);
+       if (ret < 0)
+               goto out;
+       if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
+               ret = -EINVAL;
+out:
+       kfree(sdesc);
+       return ret;
+}
+
+/*
+ * For key specific tpm requests, we will generate and send our
+ * own TPM command packets using the drivers send function.
+ */
+static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd,
+                           size_t buflen)
+{
+       int rc;
+
+       dump_tpm_buf(cmd);
+       rc = tpm_send(chip_num, cmd, buflen);
+       dump_tpm_buf(cmd);
+       if (rc > 0)
+               /* Can't return positive return codes values to keyctl */
+               rc = -EPERM;
+       return rc;
+}
+
+/*
+ * get a random value from TPM
+ */
+static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len)
+{
+       int ret;
+
+       INIT_BUF(tb);
+       store16(tb, TPM_TAG_RQU_COMMAND);
+       store32(tb, TPM_GETRANDOM_SIZE);
+       store32(tb, TPM_ORD_GETRANDOM);
+       store32(tb, len);
+       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data);
+       if (!ret)
+               memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len);
+       return ret;
+}
+
+static int my_get_random(unsigned char *buf, int len)
+{
+       struct tpm_buf *tb;
+       int ret;
+
+       tb = kmalloc(sizeof *tb, GFP_KERNEL);
+       if (!tb)
+               return -ENOMEM;
+       ret = tpm_get_random(tb, buf, len);
+
+       kfree(tb);
+       return ret;
+}
+
+/*
+ * Lock a trusted key, by extending a selected PCR.
+ *
+ * Prevents a trusted key that is sealed to PCRs from being accessed.
+ * This uses the tpm driver's extend function.
+ */
+static int pcrlock(const int pcrnum)
+{
+       unsigned char hash[SHA1_DIGEST_SIZE];
+       int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       ret = my_get_random(hash, SHA1_DIGEST_SIZE);
+       if (ret < 0)
+               return ret;
+       return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0;
+}
+
+/*
+ * Create an object specific authorisation protocol (OSAP) session
+ */
+static int osap(struct tpm_buf *tb, struct osapsess *s,
+               const unsigned char *key, uint16_t type, uint32_t handle)
+{
+       unsigned char enonce[TPM_NONCE_SIZE];
+       unsigned char ononce[TPM_NONCE_SIZE];
+       int ret;
+
+       ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE);
+       if (ret < 0)
+               return ret;
+
+       INIT_BUF(tb);
+       store16(tb, TPM_TAG_RQU_COMMAND);
+       store32(tb, TPM_OSAP_SIZE);
+       store32(tb, TPM_ORD_OSAP);
+       store16(tb, type);
+       store32(tb, handle);
+       storebytes(tb, ononce, TPM_NONCE_SIZE);
+
+       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       if (ret < 0)
+               return ret;
+
+       s->handle = LOAD32(tb->data, TPM_DATA_OFFSET);
+       memcpy(s->enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]),
+              TPM_NONCE_SIZE);
+       memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) +
+                                 TPM_NONCE_SIZE]), TPM_NONCE_SIZE);
+       return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE,
+                          enonce, TPM_NONCE_SIZE, ononce, 0, 0);
+}
+
+/*
+ * Create an object independent authorisation protocol (oiap) session
+ */
+static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
+{
+       int ret;
+
+       INIT_BUF(tb);
+       store16(tb, TPM_TAG_RQU_COMMAND);
+       store32(tb, TPM_OIAP_SIZE);
+       store32(tb, TPM_ORD_OIAP);
+       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       if (ret < 0)
+               return ret;
+
+       *handle = LOAD32(tb->data, TPM_DATA_OFFSET);
+       memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)],
+              TPM_NONCE_SIZE);
+       return 0;
+}
+
+struct tpm_digests {
+       unsigned char encauth[SHA1_DIGEST_SIZE];
+       unsigned char pubauth[SHA1_DIGEST_SIZE];
+       unsigned char xorwork[SHA1_DIGEST_SIZE * 2];
+       unsigned char xorhash[SHA1_DIGEST_SIZE];
+       unsigned char nonceodd[TPM_NONCE_SIZE];
+};
+
+/*
+ * Have the TPM seal(encrypt) the trusted key, possibly based on
+ * Platform Configuration Registers (PCRs). AUTH1 for sealing key.
+ */
+static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
+                   uint32_t keyhandle, const unsigned char *keyauth,
+                   const unsigned char *data, uint32_t datalen,
+                   unsigned char *blob, uint32_t *bloblen,
+                   const unsigned char *blobauth,
+                   const unsigned char *pcrinfo, uint32_t pcrinfosize)
+{
+       struct osapsess sess;
+       struct tpm_digests *td;
+       unsigned char cont;
+       uint32_t ordinal;
+       uint32_t pcrsize;
+       uint32_t datsize;
+       int sealinfosize;
+       int encdatasize;
+       int storedsize;
+       int ret;
+       int i;
+
+       /* alloc some work space for all the hashes */
+       td = kmalloc(sizeof *td, GFP_KERNEL);
+       if (!td)
+               return -ENOMEM;
+
+       /* get session for sealing key */
+       ret = osap(tb, &sess, keyauth, keytype, keyhandle);
+       if (ret < 0)
+               return ret;
+       dump_sess(&sess);
+
+       /* calculate encrypted authorization value */
+       memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE);
+       memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE);
+       ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash);
+       if (ret < 0)
+               return ret;
+
+       ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE);
+       if (ret < 0)
+               return ret;
+       ordinal = htonl(TPM_ORD_SEAL);
+       datsize = htonl(datalen);
+       pcrsize = htonl(pcrinfosize);
+       cont = 0;
+
+       /* encrypt data authorization key */
+       for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
+               td->encauth[i] = td->xorhash[i] ^ blobauth[i];
+
+       /* calculate authorization HMAC value */
+       if (pcrinfosize == 0) {
+               /* no pcr info specified */
+               ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
+                                  sess.enonce, td->nonceodd, cont,
+                                  sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
+                                  td->encauth, sizeof(uint32_t), &pcrsize,
+                                  sizeof(uint32_t), &datsize, datalen, data, 0,
+                                  0);
+       } else {
+               /* pcr info specified */
+               ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
+                                  sess.enonce, td->nonceodd, cont,
+                                  sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
+                                  td->encauth, sizeof(uint32_t), &pcrsize,
+                                  pcrinfosize, pcrinfo, sizeof(uint32_t),
+                                  &datsize, datalen, data, 0, 0);
+       }
+       if (ret < 0)
+               return ret;
+
+       /* build and send the TPM request packet */
+       INIT_BUF(tb);
+       store16(tb, TPM_TAG_RQU_AUTH1_COMMAND);
+       store32(tb, TPM_SEAL_SIZE + pcrinfosize + datalen);
+       store32(tb, TPM_ORD_SEAL);
+       store32(tb, keyhandle);
+       storebytes(tb, td->encauth, SHA1_DIGEST_SIZE);
+       store32(tb, pcrinfosize);
+       storebytes(tb, pcrinfo, pcrinfosize);
+       store32(tb, datalen);
+       storebytes(tb, data, datalen);
+       store32(tb, sess.handle);
+       storebytes(tb, td->nonceodd, TPM_NONCE_SIZE);
+       store8(tb, cont);
+       storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE);
+
+       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       if (ret < 0)
+               return ret;
+
+       /* calculate the size of the returned Blob */
+       sealinfosize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t));
+       encdatasize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t) +
+                            sizeof(uint32_t) + sealinfosize);
+       storedsize = sizeof(uint32_t) + sizeof(uint32_t) + sealinfosize +
+           sizeof(uint32_t) + encdatasize;
+
+       /* check the HMAC in the response */
+       ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, sess.secret,
+                            SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0,
+                            0);
+
+       /* copy the returned blob to caller */
+       if (!ret) {
+               memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
+               *bloblen = storedsize;
+       }
+       return ret;
+}
+
+/*
+ * use the AUTH2_COMMAND form of unseal, to authorize both key and blob
+ */
+static int tpm_unseal(struct tpm_buf *tb,
+                     uint32_t keyhandle, const unsigned char *keyauth,
+                     const unsigned char *blob, int bloblen,
+                     const unsigned char *blobauth,
+                     unsigned char *data, unsigned int *datalen)
+{
+       unsigned char nonceodd[TPM_NONCE_SIZE];
+       unsigned char enonce1[TPM_NONCE_SIZE];
+       unsigned char enonce2[TPM_NONCE_SIZE];
+       unsigned char authdata1[SHA1_DIGEST_SIZE];
+       unsigned char authdata2[SHA1_DIGEST_SIZE];
+       uint32_t authhandle1 = 0;
+       uint32_t authhandle2 = 0;
+       unsigned char cont = 0;
+       uint32_t ordinal;
+       uint32_t keyhndl;
+       int ret;
+
+       /* sessions for unsealing key and data */
+       ret = oiap(tb, &authhandle1, enonce1);
+       if (ret < 0) {
+               pr_info("trusted_key: oiap failed (%d)\n", ret);
+               return ret;
+       }
+       ret = oiap(tb, &authhandle2, enonce2);
+       if (ret < 0) {
+               pr_info("trusted_key: oiap failed (%d)\n", ret);
+               return ret;
+       }
+
+       ordinal = htonl(TPM_ORD_UNSEAL);
+       keyhndl = htonl(SRKHANDLE);
+       ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE);
+       if (ret < 0) {
+               pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
+               return ret;
+       }
+       ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
+                          enonce1, nonceodd, cont, sizeof(uint32_t),
+                          &ordinal, bloblen, blob, 0, 0);
+       if (ret < 0)
+               return ret;
+       ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE,
+                          enonce2, nonceodd, cont, sizeof(uint32_t),
+                          &ordinal, bloblen, blob, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       /* build and send TPM request packet */
+       INIT_BUF(tb);
+       store16(tb, TPM_TAG_RQU_AUTH2_COMMAND);
+       store32(tb, TPM_UNSEAL_SIZE + bloblen);
+       store32(tb, TPM_ORD_UNSEAL);
+       store32(tb, keyhandle);
+       storebytes(tb, blob, bloblen);
+       store32(tb, authhandle1);
+       storebytes(tb, nonceodd, TPM_NONCE_SIZE);
+       store8(tb, cont);
+       storebytes(tb, authdata1, SHA1_DIGEST_SIZE);
+       store32(tb, authhandle2);
+       storebytes(tb, nonceodd, TPM_NONCE_SIZE);
+       store8(tb, cont);
+       storebytes(tb, authdata2, SHA1_DIGEST_SIZE);
+
+       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       if (ret < 0) {
+               pr_info("trusted_key: authhmac failed (%d)\n", ret);
+               return ret;
+       }
+
+       *datalen = LOAD32(tb->data, TPM_DATA_OFFSET);
+       ret = TSS_checkhmac2(tb->data, ordinal, nonceodd,
+                            keyauth, SHA1_DIGEST_SIZE,
+                            blobauth, SHA1_DIGEST_SIZE,
+                            sizeof(uint32_t), TPM_DATA_OFFSET,
+                            *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0,
+                            0);
+       if (ret < 0) {
+               pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret);
+               return ret;
+       }
+       memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen);
+       return 0;
+}
+
+/*
+ * Have the TPM seal(encrypt) the symmetric key
+ */
+static int key_seal(struct trusted_key_payload *p,
+                   struct trusted_key_options *o)
+{
+       struct tpm_buf *tb;
+       int ret;
+
+       tb = kzalloc(sizeof *tb, GFP_KERNEL);
+       if (!tb)
+               return -ENOMEM;
+
+       /* include migratable flag at end of sealed key */
+       p->key[p->key_len] = p->migratable;
+
+       ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth,
+                      p->key, p->key_len + 1, p->blob, &p->blob_len,
+                      o->blobauth, o->pcrinfo, o->pcrinfo_len);
+       if (ret < 0)
+               pr_info("trusted_key: srkseal failed (%d)\n", ret);
+
+       kfree(tb);
+       return ret;
+}
+
+/*
+ * Have the TPM unseal(decrypt) the symmetric key
+ */
+static int key_unseal(struct trusted_key_payload *p,
+                     struct trusted_key_options *o)
+{
+       struct tpm_buf *tb;
+       int ret;
+
+       tb = kzalloc(sizeof *tb, GFP_KERNEL);
+       if (!tb)
+               return -ENOMEM;
+
+       ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
+                        o->blobauth, p->key, &p->key_len);
+       if (ret < 0)
+               pr_info("trusted_key: srkunseal failed (%d)\n", ret);
+       else
+               /* pull migratable flag out of sealed key */
+               p->migratable = p->key[--p->key_len];
+
+       kfree(tb);
+       return ret;
+}
+
+enum {
+       Opt_err = -1,
+       Opt_new, Opt_load, Opt_update,
+       Opt_keyhandle, Opt_keyauth, Opt_blobauth,
+       Opt_pcrinfo, Opt_pcrlock, Opt_migratable
+};
+
+static const match_table_t key_tokens = {
+       {Opt_new, "new"},
+       {Opt_load, "load"},
+       {Opt_update, "update"},
+       {Opt_keyhandle, "keyhandle=%s"},
+       {Opt_keyauth, "keyauth=%s"},
+       {Opt_blobauth, "blobauth=%s"},
+       {Opt_pcrinfo, "pcrinfo=%s"},
+       {Opt_pcrlock, "pcrlock=%s"},
+       {Opt_migratable, "migratable=%s"},
+       {Opt_err, NULL}
+};
+
+/* can have zero or more token= options */
+static int getoptions(char *c, struct trusted_key_payload *pay,
+                     struct trusted_key_options *opt)
+{
+       substring_t args[MAX_OPT_ARGS];
+       char *p = c;
+       int token;
+       int res;
+       unsigned long handle;
+       unsigned long lock;
+
+       while ((p = strsep(&c, " \t"))) {
+               if (*p == '\0' || *p == ' ' || *p == '\t')
+                       continue;
+               token = match_token(p, key_tokens, args);
+
+               switch (token) {
+               case Opt_pcrinfo:
+                       opt->pcrinfo_len = strlen(args[0].from) / 2;
+                       if (opt->pcrinfo_len > MAX_PCRINFO_SIZE)
+                               return -EINVAL;
+                       hex2bin(opt->pcrinfo, args[0].from, opt->pcrinfo_len);
+                       break;
+               case Opt_keyhandle:
+                       res = strict_strtoul(args[0].from, 16, &handle);
+                       if (res < 0)
+                               return -EINVAL;
+                       opt->keytype = SEAL_keytype;
+                       opt->keyhandle = handle;
+                       break;
+               case Opt_keyauth:
+                       if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
+                               return -EINVAL;
+                       hex2bin(opt->keyauth, args[0].from, SHA1_DIGEST_SIZE);
+                       break;
+               case Opt_blobauth:
+                       if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
+                               return -EINVAL;
+                       hex2bin(opt->blobauth, args[0].from, SHA1_DIGEST_SIZE);
+                       break;
+               case Opt_migratable:
+                       if (*args[0].from == '0')
+                               pay->migratable = 0;
+                       else
+                               return -EINVAL;
+                       break;
+               case Opt_pcrlock:
+                       res = strict_strtoul(args[0].from, 10, &lock);
+                       if (res < 0)
+                               return -EINVAL;
+                       opt->pcrlock = lock;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+/*
+ * datablob_parse - parse the keyctl data and fill in the
+ *                 payload and options structures
+ *
+ * On success returns 0, otherwise -EINVAL.
+ */
+static int datablob_parse(char *datablob, struct trusted_key_payload *p,
+                         struct trusted_key_options *o)
+{
+       substring_t args[MAX_OPT_ARGS];
+       long keylen;
+       int ret = -EINVAL;
+       int key_cmd;
+       char *c;
+
+       /* main command */
+       c = strsep(&datablob, " \t");
+       if (!c)
+               return -EINVAL;
+       key_cmd = match_token(c, key_tokens, args);
+       switch (key_cmd) {
+       case Opt_new:
+               /* first argument is key size */
+               c = strsep(&datablob, " \t");
+               if (!c)
+                       return -EINVAL;
+               ret = strict_strtol(c, 10, &keylen);
+               if (ret < 0 || keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE)
+                       return -EINVAL;
+               p->key_len = keylen;
+               ret = getoptions(datablob, p, o);
+               if (ret < 0)
+                       return ret;
+               ret = Opt_new;
+               break;
+       case Opt_load:
+               /* first argument is sealed blob */
+               c = strsep(&datablob, " \t");
+               if (!c)
+                       return -EINVAL;
+               p->blob_len = strlen(c) / 2;
+               if (p->blob_len > MAX_BLOB_SIZE)
+                       return -EINVAL;
+               hex2bin(p->blob, c, p->blob_len);
+               ret = getoptions(datablob, p, o);
+               if (ret < 0)
+                       return ret;
+               ret = Opt_load;
+               break;
+       case Opt_update:
+               /* all arguments are options */
+               ret = getoptions(datablob, p, o);
+               if (ret < 0)
+                       return ret;
+               ret = Opt_update;
+               break;
+       case Opt_err:
+               return -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static struct trusted_key_options *trusted_options_alloc(void)
+{
+       struct trusted_key_options *options;
+
+       options = kzalloc(sizeof *options, GFP_KERNEL);
+       if (options) {
+               /* set any non-zero defaults */
+               options->keytype = SRK_keytype;
+               options->keyhandle = SRKHANDLE;
+       }
+       return options;
+}
+
+static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
+{
+       struct trusted_key_payload *p = NULL;
+       int ret;
+
+       ret = key_payload_reserve(key, sizeof *p);
+       if (ret < 0)
+               return p;
+       p = kzalloc(sizeof *p, GFP_KERNEL);
+       if (p)
+               p->migratable = 1; /* migratable by default */
+       return p;
+}
+
+/*
+ * trusted_instantiate - create a new trusted key
+ *
+ * Unseal an existing trusted blob or, for a new key, get a
+ * random key, then seal and create a trusted key-type key,
+ * adding it to the specified keyring.
+ *
+ * On success, return 0. Otherwise return errno.
+ */
+static int trusted_instantiate(struct key *key, const void *data,
+                              size_t datalen)
+{
+       struct trusted_key_payload *payload = NULL;
+       struct trusted_key_options *options = NULL;
+       char *datablob;
+       int ret = 0;
+       int key_cmd;
+
+       if (datalen <= 0 || datalen > 32767 || !data)
+               return -EINVAL;
+
+       datablob = kmalloc(datalen + 1, GFP_KERNEL);
+       if (!datablob)
+               return -ENOMEM;
+       memcpy(datablob, data, datalen);
+       datablob[datalen] = '\0';
+
+       options = trusted_options_alloc();
+       if (!options) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       payload = trusted_payload_alloc(key);
+       if (!payload) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       key_cmd = datablob_parse(datablob, payload, options);
+       if (key_cmd < 0) {
+               ret = key_cmd;
+               goto out;
+       }
+
+       dump_payload(payload);
+       dump_options(options);
+
+       switch (key_cmd) {
+       case Opt_load:
+               ret = key_unseal(payload, options);
+               dump_payload(payload);
+               dump_options(options);
+               if (ret < 0)
+                       pr_info("trusted_key: key_unseal failed (%d)\n", ret);
+               break;
+       case Opt_new:
+               ret = my_get_random(payload->key, payload->key_len);
+               if (ret < 0) {
+                       pr_info("trusted_key: key_create failed (%d)\n", ret);
+                       goto out;
+               }
+               ret = key_seal(payload, options);
+               if (ret < 0)
+                       pr_info("trusted_key: key_seal failed (%d)\n", ret);
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+       if (!ret && options->pcrlock)
+               ret = pcrlock(options->pcrlock);
+out:
+       kfree(datablob);
+       kfree(options);
+       if (!ret)
+               rcu_assign_pointer(key->payload.data, payload);
+       else
+               kfree(payload);
+       return ret;
+}
+
+static void trusted_rcu_free(struct rcu_head *rcu)
+{
+       struct trusted_key_payload *p;
+
+       p = container_of(rcu, struct trusted_key_payload, rcu);
+       memset(p->key, 0, p->key_len);
+       kfree(p);
+}
+
+/*
+ * trusted_update - reseal an existing key with new PCR values
+ */
+static int trusted_update(struct key *key, const void *data, size_t datalen)
+{
+       struct trusted_key_payload *p = key->payload.data;
+       struct trusted_key_payload *new_p;
+       struct trusted_key_options *new_o;
+       char *datablob;
+       int ret = 0;
+
+       if (!p->migratable)
+               return -EPERM;
+       if (datalen <= 0 || datalen > 32767 || !data)
+               return -EINVAL;
+
+       datablob = kmalloc(datalen + 1, GFP_KERNEL);
+       if (!datablob)
+               return -ENOMEM;
+       new_o = trusted_options_alloc();
+       if (!new_o) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       new_p = trusted_payload_alloc(key);
+       if (!new_p) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       memcpy(datablob, data, datalen);
+       datablob[datalen] = '\0';
+       ret = datablob_parse(datablob, new_p, new_o);
+       if (ret != Opt_update) {
+               ret = -EINVAL;
+               goto out;
+       }
+       /* copy old key values, and reseal with new pcrs */
+       new_p->migratable = p->migratable;
+       new_p->key_len = p->key_len;
+       memcpy(new_p->key, p->key, p->key_len);
+       dump_payload(p);
+       dump_payload(new_p);
+
+       ret = key_seal(new_p, new_o);
+       if (ret < 0) {
+               pr_info("trusted_key: key_seal failed (%d)\n", ret);
+               kfree(new_p);
+               goto out;
+       }
+       if (new_o->pcrlock) {
+               ret = pcrlock(new_o->pcrlock);
+               if (ret < 0) {
+                       pr_info("trusted_key: pcrlock failed (%d)\n", ret);
+                       kfree(new_p);
+                       goto out;
+               }
+       }
+       rcu_assign_pointer(key->payload.data, new_p);
+       call_rcu(&p->rcu, trusted_rcu_free);
+out:
+       kfree(datablob);
+       kfree(new_o);
+       return ret;
+}
+
+/*
+ * trusted_read - copy the sealed blob data to userspace in hex.
+ * On success, return to userspace the trusted key datablob size.
+ */
+static long trusted_read(const struct key *key, char __user *buffer,
+                        size_t buflen)
+{
+       struct trusted_key_payload *p;
+       char *ascii_buf;
+       char *bufp;
+       int i;
+
+       p = rcu_dereference_protected(key->payload.data,
+                       rwsem_is_locked(&((struct key *)key)->sem));
+       if (!p)
+               return -EINVAL;
+       if (!buffer || buflen <= 0)
+               return 2 * p->blob_len;
+       ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL);
+       if (!ascii_buf)
+               return -ENOMEM;
+
+       bufp = ascii_buf;
+       for (i = 0; i < p->blob_len; i++)
+               bufp = pack_hex_byte(bufp, p->blob[i]);
+       if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) {
+               kfree(ascii_buf);
+               return -EFAULT;
+       }
+       kfree(ascii_buf);
+       return 2 * p->blob_len;
+}
+
+/*
+ * trusted_destroy - before freeing the key, clear the decrypted data
+ */
+static void trusted_destroy(struct key *key)
+{
+       struct trusted_key_payload *p = key->payload.data;
+
+       if (!p)
+               return;
+       memset(p->key, 0, p->key_len);
+       kfree(key->payload.data);
+}
+
+struct key_type key_type_trusted = {
+       .name = "trusted",
+       .instantiate = trusted_instantiate,
+       .update = trusted_update,
+       .match = user_match,
+       .destroy = trusted_destroy,
+       .describe = user_describe,
+       .read = trusted_read,
+};
+
+EXPORT_SYMBOL_GPL(key_type_trusted);
+
+static void trusted_shash_release(void)
+{
+       if (hashalg)
+               crypto_free_shash(hashalg);
+       if (hmacalg)
+               crypto_free_shash(hmacalg);
+}
+
+static int __init trusted_shash_alloc(void)
+{
+       int ret;
+
+       hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(hmacalg)) {
+               pr_info("trusted_key: could not allocate crypto %s\n",
+                       hmac_alg);
+               return PTR_ERR(hmacalg);
+       }
+
+       hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(hashalg)) {
+               pr_info("trusted_key: could not allocate crypto %s\n",
+                       hash_alg);
+               ret = PTR_ERR(hashalg);
+               goto hashalg_fail;
+       }
+
+       return 0;
+
+hashalg_fail:
+       crypto_free_shash(hmacalg);
+       return ret;
+}
+
+static int __init init_trusted(void)
+{
+       int ret;
+
+       ret = trusted_shash_alloc();
+       if (ret < 0)
+               return ret;
+       ret = register_key_type(&key_type_trusted);
+       if (ret < 0)
+               trusted_shash_release();
+       return ret;
+}
+
+static void __exit cleanup_trusted(void)
+{
+       trusted_shash_release();
+       unregister_key_type(&key_type_trusted);
+}
+
+late_initcall(init_trusted);
+module_exit(cleanup_trusted);
+
+MODULE_LICENSE("GPL");
diff --git a/security/keys/trusted_defined.h b/security/keys/trusted_defined.h
new file mode 100644 (file)
index 0000000..3249fbd
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef __TRUSTED_KEY_H
+#define __TRUSTED_KEY_H
+
+/* implementation specific TPM constants */
+#define MAX_PCRINFO_SIZE               64
+#define MAX_BUF_SIZE                   512
+#define TPM_GETRANDOM_SIZE             14
+#define TPM_OSAP_SIZE                  36
+#define TPM_OIAP_SIZE                  10
+#define TPM_SEAL_SIZE                  87
+#define TPM_UNSEAL_SIZE                        104
+#define TPM_SIZE_OFFSET                        2
+#define TPM_RETURN_OFFSET              6
+#define TPM_DATA_OFFSET                        10
+
+#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset]))
+#define LOAD32N(buffer, offset)        (*(uint32_t *)&buffer[offset])
+#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset]))
+
+struct tpm_buf {
+       int len;
+       unsigned char data[MAX_BUF_SIZE];
+};
+
+#define INIT_BUF(tb) (tb->len = 0)
+
+struct osapsess {
+       uint32_t handle;
+       unsigned char secret[SHA1_DIGEST_SIZE];
+       unsigned char enonce[TPM_NONCE_SIZE];
+};
+
+/* discrete values, but have to store in uint16_t for TPM use */
+enum {
+       SEAL_keytype = 1,
+       SRK_keytype = 4
+};
+
+struct trusted_key_options {
+       uint16_t keytype;
+       uint32_t keyhandle;
+       unsigned char keyauth[SHA1_DIGEST_SIZE];
+       unsigned char blobauth[SHA1_DIGEST_SIZE];
+       uint32_t pcrinfo_len;
+       unsigned char pcrinfo[MAX_PCRINFO_SIZE];
+       int pcrlock;
+};
+
+#define TPM_DEBUG 0
+
+#if TPM_DEBUG
+static inline void dump_options(struct trusted_key_options *o)
+{
+       pr_info("trusted_key: sealing key type %d\n", o->keytype);
+       pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle);
+       pr_info("trusted_key: pcrlock %d\n", o->pcrlock);
+       pr_info("trusted_key: pcrinfo %d\n", o->pcrinfo_len);
+       print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE,
+                      16, 1, o->pcrinfo, o->pcrinfo_len, 0);
+}
+
+static inline void dump_payload(struct trusted_key_payload *p)
+{
+       pr_info("trusted_key: key_len %d\n", p->key_len);
+       print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE,
+                      16, 1, p->key, p->key_len, 0);
+       pr_info("trusted_key: bloblen %d\n", p->blob_len);
+       print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE,
+                      16, 1, p->blob, p->blob_len, 0);
+       pr_info("trusted_key: migratable %d\n", p->migratable);
+}
+
+static inline void dump_sess(struct osapsess *s)
+{
+       print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE,
+                      16, 1, &s->handle, 4, 0);
+       pr_info("trusted-key: secret:\n");
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
+                      16, 1, &s->secret, SHA1_DIGEST_SIZE, 0);
+       pr_info("trusted-key: enonce:\n");
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
+                      16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0);
+}
+
+static inline void dump_tpm_buf(unsigned char *buf)
+{
+       int len;
+
+       pr_info("\ntrusted-key: tpm buffer\n");
+       len = LOAD32(buf, TPM_SIZE_OFFSET);
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0);
+}
+#else
+static inline void dump_options(struct trusted_key_options *o)
+{
+}
+
+static inline void dump_payload(struct trusted_key_payload *p)
+{
+}
+
+static inline void dump_sess(struct osapsess *s)
+{
+}
+
+static inline void dump_tpm_buf(unsigned char *buf)
+{
+}
+#endif
+
+static inline void store8(struct tpm_buf *buf, const unsigned char value)
+{
+       buf->data[buf->len++] = value;
+}
+
+static inline void store16(struct tpm_buf *buf, const uint16_t value)
+{
+       *(uint16_t *) & buf->data[buf->len] = htons(value);
+       buf->len += sizeof value;
+}
+
+static inline void store32(struct tpm_buf *buf, const uint32_t value)
+{
+       *(uint32_t *) & buf->data[buf->len] = htonl(value);
+       buf->len += sizeof value;
+}
+
+static inline void storebytes(struct tpm_buf *buf, const unsigned char *in,
+                             const int len)
+{
+       memcpy(buf->data + buf->len, in, len);
+       buf->len += len;
+}
+#endif
index 6f637d2678ac213cbed1d1bd5b0d778d10f56562..e276eb468536d0df5b091afa3f08fbf2352a8c81 100644 (file)
@@ -2525,7 +2525,10 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
+       if ((sbsec->flags & SE_SBINITIALIZED) &&
+           (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
+               newsid = sbsec->mntpoint_sid;
+       else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
                rc = security_transition_sid(sid, dsec->sid,
                                             inode_mode_to_security_class(inode->i_mode),
                                             &newsid);
index e94e82f738188381c582d59e26aca94b867ac064..5615081b73eca403e438678fcea782dc06e580e3 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/audit.h>
 #include <linux/lsm_audit.h>
 #include <linux/in6.h>
-#include <linux/path.h>
 #include <asm/system.h>
 #include "flask.h"
 #include "av_permissions.h"
index 8858d2b2d4b6ad1dd1b005b20a06afa4a3505d03..7ed3663332ecf16a9f8c237e00b2963fe561cfa7 100644 (file)
@@ -142,7 +142,7 @@ struct security_class_mapping secclass_map[] = {
            "node_bind", "name_connect", NULL } },
        { "memprotect", { "mmap_zero", NULL } },
        { "peer", { "recv", NULL } },
-       { "capability2", { "mac_override", "mac_admin", NULL } },
+       { "capability2", { "mac_override", "mac_admin", "syslog", NULL } },
        { "kernel_service", { "use_as_override", "create_files_as", NULL } },
        { "tun_socket",
          { COMMON_SOCK_PERMS, NULL } },
index 75ec0c6ebacdeda7e64d0838e4d86d6eea1f3e3e..8b02b2137da25ce114e602d60a22b009dbbe82e1 100644 (file)
@@ -65,6 +65,8 @@ static struct nlmsg_perm nlmsg_route_perms[] =
        { RTM_NEWADDRLABEL,     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
        { RTM_DELADDRLABEL,     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
        { RTM_GETADDRLABEL,     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+       { RTM_GETDCB,           NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+       { RTM_SETDCB,           NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
 };
 
 static struct nlmsg_perm nlmsg_firewall_perms[] =
index 43deac2194912522d1d7a719f3ab1cb84408230c..ea39cb742ae5b0422d90643024ce8a3bf812973f 100644 (file)
@@ -141,19 +141,24 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 
 {
-       char *page;
+       char *page = NULL;
        ssize_t length;
        int new_value;
 
+       length = -ENOMEM;
        if (count >= PAGE_SIZE)
-               return -ENOMEM;
-       if (*ppos != 0) {
-               /* No partial writes. */
-               return -EINVAL;
-       }
+               goto out;
+
+       /* No partial writes. */
+       length = EINVAL;
+       if (*ppos != 0)
+               goto out;
+
+       length = -ENOMEM;
        page = (char *)get_zeroed_page(GFP_KERNEL);
        if (!page)
-               return -ENOMEM;
+               goto out;
+
        length = -EFAULT;
        if (copy_from_user(page, buf, count))
                goto out;
@@ -268,20 +273,25 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 
 {
-       char *page;
+       char *page = NULL;
        ssize_t length;
        int new_value;
        extern int selinux_disable(void);
 
+       length = -ENOMEM;
        if (count >= PAGE_SIZE)
-               return -ENOMEM;
-       if (*ppos != 0) {
-               /* No partial writes. */
-               return -EINVAL;
-       }
+               goto out;;
+
+       /* No partial writes. */
+       length = -EINVAL;
+       if (*ppos != 0)
+               goto out;
+
+       length = -ENOMEM;
        page = (char *)get_zeroed_page(GFP_KERNEL);
        if (!page)
-               return -ENOMEM;
+               goto out;
+
        length = -EFAULT;
        if (copy_from_user(page, buf, count))
                goto out;
@@ -292,7 +302,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
 
        if (new_value) {
                length = selinux_disable();
-               if (length < 0)
+               if (length)
                        goto out;
                audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
                        "selinux=0 auid=%u ses=%u",
@@ -493,7 +503,6 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
                              size_t count, loff_t *ppos)
 
 {
-       int ret;
        ssize_t length;
        void *data = NULL;
 
@@ -503,17 +512,19 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
        if (length)
                goto out;
 
-       if (*ppos != 0) {
-               /* No partial writes. */
-               length = -EINVAL;
+       /* No partial writes. */
+       length = -EINVAL;
+       if (*ppos != 0)
                goto out;
-       }
 
-       if ((count > 64 * 1024 * 1024)
-           || (data = vmalloc(count)) == NULL) {
-               length = -ENOMEM;
+       length = -EFBIG;
+       if (count > 64 * 1024 * 1024)
+               goto out;
+
+       length = -ENOMEM;
+       data = vmalloc(count);
+       if (!data)
                goto out;
-       }
 
        length = -EFAULT;
        if (copy_from_user(data, buf, count) != 0)
@@ -523,23 +534,19 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
        if (length)
                goto out;
 
-       ret = sel_make_bools();
-       if (ret) {
-               length = ret;
+       length = sel_make_bools();
+       if (length)
                goto out1;
-       }
 
-       ret = sel_make_classes();
-       if (ret) {
-               length = ret;
+       length = sel_make_classes();
+       if (length)
                goto out1;
-       }
 
-       ret = sel_make_policycap();
-       if (ret)
-               length = ret;
-       else
-               length = count;
+       length = sel_make_policycap();
+       if (length)
+               goto out1;
+
+       length = count;
 
 out1:
        audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
@@ -559,26 +566,26 @@ static const struct file_operations sel_load_ops = {
 
 static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
 {
-       char *canon;
+       char *canon = NULL;
        u32 sid, len;
        ssize_t length;
 
        length = task_has_security(current, SECURITY__CHECK_CONTEXT);
        if (length)
-               return length;
+               goto out;
 
        length = security_context_to_sid(buf, size, &sid);
-       if (length < 0)
-               return length;
+       if (length)
+               goto out;
 
        length = security_sid_to_context(sid, &canon, &len);
-       if (length < 0)
-               return length;
+       if (length)
+               goto out;
 
+       length = -ERANGE;
        if (len > SIMPLE_TRANSACTION_LIMIT) {
                printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
                        "payload max\n", __func__, len);
-               length = -ERANGE;
                goto out;
        }
 
@@ -602,23 +609,28 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
 static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
                                      size_t count, loff_t *ppos)
 {
-       char *page;
+       char *page = NULL;
        ssize_t length;
        unsigned int new_value;
 
        length = task_has_security(current, SECURITY__SETCHECKREQPROT);
        if (length)
-               return length;
+               goto out;
 
+       length = -ENOMEM;
        if (count >= PAGE_SIZE)
-               return -ENOMEM;
-       if (*ppos != 0) {
-               /* No partial writes. */
-               return -EINVAL;
-       }
+               goto out;
+
+       /* No partial writes. */
+       length = -EINVAL;
+       if (*ppos != 0)
+               goto out;
+
+       length = -ENOMEM;
        page = (char *)get_zeroed_page(GFP_KERNEL);
        if (!page)
-               return -ENOMEM;
+               goto out;
+
        length = -EFAULT;
        if (copy_from_user(page, buf, count))
                goto out;
@@ -693,7 +705,7 @@ static const struct file_operations transaction_ops = {
 
 static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
 {
-       char *scon, *tcon;
+       char *scon = NULL, *tcon = NULL;
        u32 ssid, tsid;
        u16 tclass;
        struct av_decision avd;
@@ -701,27 +713,29 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
 
        length = task_has_security(current, SECURITY__COMPUTE_AV);
        if (length)
-               return length;
+               goto out;
 
        length = -ENOMEM;
        scon = kzalloc(size + 1, GFP_KERNEL);
        if (!scon)
-               return length;
+               goto out;
 
+       length = -ENOMEM;
        tcon = kzalloc(size + 1, GFP_KERNEL);
        if (!tcon)
                goto out;
 
        length = -EINVAL;
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
-               goto out2;
+               goto out;
 
        length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
+
        length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
        security_compute_av_user(ssid, tsid, tclass, &avd);
 
@@ -730,133 +744,131 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
                          avd.allowed, 0xffffffff,
                          avd.auditallow, avd.auditdeny,
                          avd.seqno, avd.flags);
-out2:
-       kfree(tcon);
 out:
+       kfree(tcon);
        kfree(scon);
        return length;
 }
 
 static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 {
-       char *scon, *tcon;
+       char *scon = NULL, *tcon = NULL;
        u32 ssid, tsid, newsid;
        u16 tclass;
        ssize_t length;
-       char *newcon;
+       char *newcon = NULL;
        u32 len;
 
        length = task_has_security(current, SECURITY__COMPUTE_CREATE);
        if (length)
-               return length;
+               goto out;
 
        length = -ENOMEM;
        scon = kzalloc(size + 1, GFP_KERNEL);
        if (!scon)
-               return length;
+               goto out;
 
+       length = -ENOMEM;
        tcon = kzalloc(size + 1, GFP_KERNEL);
        if (!tcon)
                goto out;
 
        length = -EINVAL;
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
-               goto out2;
+               goto out;
 
        length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
+
        length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
        length = security_transition_sid_user(ssid, tsid, tclass, &newsid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
        length = security_sid_to_context(newsid, &newcon, &len);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
+       length = -ERANGE;
        if (len > SIMPLE_TRANSACTION_LIMIT) {
                printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
                        "payload max\n", __func__, len);
-               length = -ERANGE;
-               goto out3;
+               goto out;
        }
 
        memcpy(buf, newcon, len);
        length = len;
-out3:
+out:
        kfree(newcon);
-out2:
        kfree(tcon);
-out:
        kfree(scon);
        return length;
 }
 
 static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
 {
-       char *scon, *tcon;
+       char *scon = NULL, *tcon = NULL;
        u32 ssid, tsid, newsid;
        u16 tclass;
        ssize_t length;
-       char *newcon;
+       char *newcon = NULL;
        u32 len;
 
        length = task_has_security(current, SECURITY__COMPUTE_RELABEL);
        if (length)
-               return length;
+               goto out;
 
        length = -ENOMEM;
        scon = kzalloc(size + 1, GFP_KERNEL);
        if (!scon)
-               return length;
+               goto out;
 
+       length = -ENOMEM;
        tcon = kzalloc(size + 1, GFP_KERNEL);
        if (!tcon)
                goto out;
 
        length = -EINVAL;
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
-               goto out2;
+               goto out;
 
        length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
+
        length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
        length = security_change_sid(ssid, tsid, tclass, &newsid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
        length = security_sid_to_context(newsid, &newcon, &len);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
-       if (len > SIMPLE_TRANSACTION_LIMIT) {
-               length = -ERANGE;
-               goto out3;
-       }
+       length = -ERANGE;
+       if (len > SIMPLE_TRANSACTION_LIMIT)
+               goto out;
 
        memcpy(buf, newcon, len);
        length = len;
-out3:
+out:
        kfree(newcon);
-out2:
        kfree(tcon);
-out:
        kfree(scon);
        return length;
 }
 
 static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
 {
-       char *con, *user, *ptr;
-       u32 sid, *sids;
+       char *con = NULL, *user = NULL, *ptr;
+       u32 sid, *sids = NULL;
        ssize_t length;
        char *newcon;
        int i, rc;
@@ -864,28 +876,29 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
 
        length = task_has_security(current, SECURITY__COMPUTE_USER);
        if (length)
-               return length;
+               goto out;;
 
        length = -ENOMEM;
        con = kzalloc(size + 1, GFP_KERNEL);
        if (!con)
-               return length;
+               goto out;;
 
+       length = -ENOMEM;
        user = kzalloc(size + 1, GFP_KERNEL);
        if (!user)
                goto out;
 
        length = -EINVAL;
        if (sscanf(buf, "%s %s", con, user) != 2)
-               goto out2;
+               goto out;
 
        length = security_context_to_sid(con, strlen(con) + 1, &sid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
        length = security_get_user_sids(sid, user, &sids, &nsids);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
        length = sprintf(buf, "%u", nsids) + 1;
        ptr = buf + length;
@@ -893,82 +906,80 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
                rc = security_sid_to_context(sids[i], &newcon, &len);
                if (rc) {
                        length = rc;
-                       goto out3;
+                       goto out;
                }
                if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) {
                        kfree(newcon);
                        length = -ERANGE;
-                       goto out3;
+                       goto out;
                }
                memcpy(ptr, newcon, len);
                kfree(newcon);
                ptr += len;
                length += len;
        }
-out3:
+out:
        kfree(sids);
-out2:
        kfree(user);
-out:
        kfree(con);
        return length;
 }
 
 static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
 {
-       char *scon, *tcon;
+       char *scon = NULL, *tcon = NULL;
        u32 ssid, tsid, newsid;
        u16 tclass;
        ssize_t length;
-       char *newcon;
+       char *newcon = NULL;
        u32 len;
 
        length = task_has_security(current, SECURITY__COMPUTE_MEMBER);
        if (length)
-               return length;
+               goto out;
 
        length = -ENOMEM;
        scon = kzalloc(size + 1, GFP_KERNEL);
        if (!scon)
-               return length;
+               goto out;;
 
+       length = -ENOMEM;
        tcon = kzalloc(size + 1, GFP_KERNEL);
        if (!tcon)
                goto out;
 
        length = -EINVAL;
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
-               goto out2;
+               goto out;
 
        length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
+
        length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
        length = security_member_sid(ssid, tsid, tclass, &newsid);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
        length = security_sid_to_context(newsid, &newcon, &len);
-       if (length < 0)
-               goto out2;
+       if (length)
+               goto out;
 
+       length = -ERANGE;
        if (len > SIMPLE_TRANSACTION_LIMIT) {
                printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
                        "payload max\n", __func__, len);
-               length = -ERANGE;
-               goto out3;
+               goto out;
        }
 
        memcpy(buf, newcon, len);
        length = len;
-out3:
+out:
        kfree(newcon);
-out2:
        kfree(tcon);
-out:
        kfree(scon);
        return length;
 }
@@ -978,7 +989,6 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode)
        struct inode *ret = new_inode(sb);
 
        if (ret) {
-               ret->i_ino = get_next_ino();
                ret->i_mode = mode;
                ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
        }
@@ -998,16 +1008,14 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
 
        mutex_lock(&sel_mutex);
 
-       if (index >= bool_num || strcmp(name, bool_pending_names[index])) {
-               ret = -EINVAL;
+       ret = -EINVAL;
+       if (index >= bool_num || strcmp(name, bool_pending_names[index]))
                goto out;
-       }
 
+       ret = -ENOMEM;
        page = (char *)get_zeroed_page(GFP_KERNEL);
-       if (!page) {
-               ret = -ENOMEM;
+       if (!page)
                goto out;
-       }
 
        cur_enforcing = security_get_bool_value(index);
        if (cur_enforcing < 0) {
@@ -1019,8 +1027,7 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
        ret = simple_read_from_buffer(buf, count, ppos, page, length);
 out:
        mutex_unlock(&sel_mutex);
-       if (page)
-               free_page((unsigned long)page);
+       free_page((unsigned long)page);
        return ret;
 }
 
@@ -1040,26 +1047,23 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
        if (length)
                goto out;
 
-       if (index >= bool_num || strcmp(name, bool_pending_names[index])) {
-               length = -EINVAL;
+       length = -EINVAL;
+       if (index >= bool_num || strcmp(name, bool_pending_names[index]))
                goto out;
-       }
 
-       if (count >= PAGE_SIZE) {
-               length = -ENOMEM;
+       length = -ENOMEM;
+       if (count >= PAGE_SIZE)
                goto out;
-       }
 
-       if (*ppos != 0) {
-               /* No partial writes. */
-               length = -EINVAL;
+       /* No partial writes. */
+       length = -EINVAL;
+       if (*ppos != 0)
                goto out;
-       }
+
+       length = -ENOMEM;
        page = (char *)get_zeroed_page(GFP_KERNEL);
-       if (!page) {
-               length = -ENOMEM;
+       if (!page)
                goto out;
-       }
 
        length = -EFAULT;
        if (copy_from_user(page, buf, count))
@@ -1077,8 +1081,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
 
 out:
        mutex_unlock(&sel_mutex);
-       if (page)
-               free_page((unsigned long) page);
+       free_page((unsigned long) page);
        return length;
 }
 
@@ -1102,19 +1105,19 @@ static ssize_t sel_commit_bools_write(struct file *filep,
        if (length)
                goto out;
 
-       if (count >= PAGE_SIZE) {
-               length = -ENOMEM;
+       length = -ENOMEM;
+       if (count >= PAGE_SIZE)
                goto out;
-       }
-       if (*ppos != 0) {
-               /* No partial writes. */
+
+       /* No partial writes. */
+       length = -EINVAL;
+       if (*ppos != 0)
                goto out;
-       }
+
+       length = -ENOMEM;
        page = (char *)get_zeroed_page(GFP_KERNEL);
-       if (!page) {
-               length = -ENOMEM;
+       if (!page)
                goto out;
-       }
 
        length = -EFAULT;
        if (copy_from_user(page, buf, count))
@@ -1124,15 +1127,16 @@ static ssize_t sel_commit_bools_write(struct file *filep,
        if (sscanf(page, "%d", &new_value) != 1)
                goto out;
 
+       length = 0;
        if (new_value && bool_pending_values)
-               security_set_bools(bool_num, bool_pending_values);
+               length = security_set_bools(bool_num, bool_pending_values);
 
-       length = count;
+       if (!length)
+               length = count;
 
 out:
        mutex_unlock(&sel_mutex);
-       if (page)
-               free_page((unsigned long) page);
+       free_page((unsigned long) page);
        return length;
 }
 
@@ -1173,7 +1177,7 @@ static void sel_remove_entries(struct dentry *de)
 
 static int sel_make_bools(void)
 {
-       int i, ret = 0;
+       int i, ret;
        ssize_t len;
        struct dentry *dentry = NULL;
        struct dentry *dir = bool_dir;
@@ -1194,38 +1198,40 @@ static int sel_make_bools(void)
 
        sel_remove_entries(dir);
 
+       ret = -ENOMEM;
        page = (char *)get_zeroed_page(GFP_KERNEL);
        if (!page)
-               return -ENOMEM;
+               goto out;
 
        ret = security_get_bools(&num, &names, &values);
-       if (ret != 0)
+       if (ret)
                goto out;
 
        for (i = 0; i < num; i++) {
+               ret = -ENOMEM;
                dentry = d_alloc_name(dir, names[i]);
-               if (!dentry) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
+               if (!dentry)
+                       goto out;
+
+               ret = -ENOMEM;
                inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
-               if (!inode) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
+               if (!inode)
+                       goto out;
 
+               ret = -EINVAL;
                len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
-               if (len < 0) {
-                       ret = -EINVAL;
-                       goto err;
-               } else if (len >= PAGE_SIZE) {
-                       ret = -ENAMETOOLONG;
-                       goto err;
-               }
+               if (len < 0)
+                       goto out;
+
+               ret = -ENAMETOOLONG;
+               if (len >= PAGE_SIZE)
+                       goto out;
+
                isec = (struct inode_security_struct *)inode->i_security;
                ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid);
                if (ret)
-                       goto err;
+                       goto out;
+
                isec->sid = sid;
                isec->initialized = 1;
                inode->i_fop = &sel_bool_ops;
@@ -1235,10 +1241,12 @@ static int sel_make_bools(void)
        bool_num = num;
        bool_pending_names = names;
        bool_pending_values = values;
+
+       free_page((unsigned long)page);
+       return 0;
 out:
        free_page((unsigned long)page);
-       return ret;
-err:
+
        if (names) {
                for (i = 0; i < num; i++)
                        kfree(names[i]);
@@ -1246,8 +1254,8 @@ err:
        }
        kfree(values);
        sel_remove_entries(dir);
-       ret = -ENOMEM;
-       goto out;
+
+       return ret;
 }
 
 #define NULL_FILE_NAME "null"
@@ -1269,47 +1277,41 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
                                             size_t count, loff_t *ppos)
 
 {
-       char *page;
+       char *page = NULL;
        ssize_t ret;
        int new_value;
 
-       if (count >= PAGE_SIZE) {
-               ret = -ENOMEM;
+       ret = task_has_security(current, SECURITY__SETSECPARAM);
+       if (ret)
                goto out;
-       }
 
-       if (*ppos != 0) {
-               /* No partial writes. */
-               ret = -EINVAL;
+       ret = -ENOMEM;
+       if (count >= PAGE_SIZE)
                goto out;
-       }
 
+       /* No partial writes. */
+       ret = -EINVAL;
+       if (*ppos != 0)
+               goto out;
+
+       ret = -ENOMEM;
        page = (char *)get_zeroed_page(GFP_KERNEL);
-       if (!page) {
-               ret = -ENOMEM;
+       if (!page)
                goto out;
-       }
 
-       if (copy_from_user(page, buf, count)) {
-               ret = -EFAULT;
-               goto out_free;
-       }
+       ret = -EFAULT;
+       if (copy_from_user(page, buf, count))
+               goto out;
 
-       if (sscanf(page, "%u", &new_value) != 1) {
-               ret = -EINVAL;
+       ret = -EINVAL;
+       if (sscanf(page, "%u", &new_value) != 1)
                goto out;
-       }
 
-       if (new_value != avc_cache_threshold) {
-               ret = task_has_security(current, SECURITY__SETSECPARAM);
-               if (ret)
-                       goto out_free;
-               avc_cache_threshold = new_value;
-       }
+       avc_cache_threshold = new_value;
+
        ret = count;
-out_free:
-       free_page((unsigned long)page);
 out:
+       free_page((unsigned long)page);
        return ret;
 }
 
@@ -1317,19 +1319,18 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
                                       size_t count, loff_t *ppos)
 {
        char *page;
-       ssize_t ret = 0;
+       ssize_t length;
 
        page = (char *)__get_free_page(GFP_KERNEL);
-       if (!page) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       ret = avc_get_hash_stats(page);
-       if (ret >= 0)
-               ret = simple_read_from_buffer(buf, count, ppos, page, ret);
+       if (!page)
+               return -ENOMEM;
+
+       length = avc_get_hash_stats(page);
+       if (length >= 0)
+               length = simple_read_from_buffer(buf, count, ppos, page, length);
        free_page((unsigned long)page);
-out:
-       return ret;
+
+       return length;
 }
 
 static const struct file_operations sel_avc_cache_threshold_ops = {
@@ -1411,7 +1412,7 @@ static const struct file_operations sel_avc_cache_stats_ops = {
 
 static int sel_make_avc_files(struct dentry *dir)
 {
-       int i, ret = 0;
+       int i;
        static struct tree_descr files[] = {
                { "cache_threshold",
                  &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR },
@@ -1426,22 +1427,19 @@ static int sel_make_avc_files(struct dentry *dir)
                struct dentry *dentry;
 
                dentry = d_alloc_name(dir, files[i].name);
-               if (!dentry) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+               if (!dentry)
+                       return -ENOMEM;
 
                inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
-               if (!inode) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+               if (!inode)
+                       return -ENOMEM;
+
                inode->i_fop = files[i].ops;
                inode->i_ino = ++sel_last_ino;
                d_add(dentry, inode);
        }
-out:
-       return ret;
+
+       return 0;
 }
 
 static ssize_t sel_read_initcon(struct file *file, char __user *buf,
@@ -1455,7 +1453,7 @@ static ssize_t sel_read_initcon(struct file *file, char __user *buf,
        inode = file->f_path.dentry->d_inode;
        sid = inode->i_ino&SEL_INO_MASK;
        ret = security_sid_to_context(sid, &con, &len);
-       if (ret < 0)
+       if (ret)
                return ret;
 
        ret = simple_read_from_buffer(buf, count, ppos, con, len);
@@ -1470,28 +1468,25 @@ static const struct file_operations sel_initcon_ops = {
 
 static int sel_make_initcon_files(struct dentry *dir)
 {
-       int i, ret = 0;
+       int i;
 
        for (i = 1; i <= SECINITSID_NUM; i++) {
                struct inode *inode;
                struct dentry *dentry;
                dentry = d_alloc_name(dir, security_get_initial_sid_context(i));
-               if (!dentry) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+               if (!dentry)
+                       return -ENOMEM;
 
                inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
-               if (!inode) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+               if (!inode)
+                       return -ENOMEM;
+
                inode->i_fop = &sel_initcon_ops;
                inode->i_ino = i|SEL_INITCON_INO_OFFSET;
                d_add(dentry, inode);
        }
-out:
-       return ret;
+
+       return 0;
 }
 
 static inline unsigned int sel_div(unsigned long a, unsigned long b)
@@ -1527,15 +1522,13 @@ static ssize_t sel_read_class(struct file *file, char __user *buf,
        unsigned long ino = file->f_path.dentry->d_inode->i_ino;
 
        page = (char *)__get_free_page(GFP_KERNEL);
-       if (!page) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!page)
+               return -ENOMEM;
 
        len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino));
        rc = simple_read_from_buffer(buf, count, ppos, page, len);
        free_page((unsigned long)page);
-out:
+
        return rc;
 }
 
@@ -1552,15 +1545,13 @@ static ssize_t sel_read_perm(struct file *file, char __user *buf,
        unsigned long ino = file->f_path.dentry->d_inode->i_ino;
 
        page = (char *)__get_free_page(GFP_KERNEL);
-       if (!page) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!page)
+               return -ENOMEM;
 
        len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_perm(ino));
        rc = simple_read_from_buffer(buf, count, ppos, page, len);
        free_page((unsigned long)page);
-out:
+
        return rc;
 }
 
@@ -1591,39 +1582,37 @@ static const struct file_operations sel_policycap_ops = {
 static int sel_make_perm_files(char *objclass, int classvalue,
                                struct dentry *dir)
 {
-       int i, rc = 0, nperms;
+       int i, rc, nperms;
        char **perms;
 
        rc = security_get_permissions(objclass, &perms, &nperms);
        if (rc)
-               goto out;
+               return rc;
 
        for (i = 0; i < nperms; i++) {
                struct inode *inode;
                struct dentry *dentry;
 
+               rc = -ENOMEM;
                dentry = d_alloc_name(dir, perms[i]);
-               if (!dentry) {
-                       rc = -ENOMEM;
-                       goto out1;
-               }
+               if (!dentry)
+                       goto out;
 
+               rc = -ENOMEM;
                inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
-               if (!inode) {
-                       rc = -ENOMEM;
-                       goto out1;
-               }
+               if (!inode)
+                       goto out;
+
                inode->i_fop = &sel_perm_ops;
                /* i+1 since perm values are 1-indexed */
                inode->i_ino = sel_perm_to_ino(classvalue, i + 1);
                d_add(dentry, inode);
        }
-
-out1:
+       rc = 0;
+out:
        for (i = 0; i < nperms; i++)
                kfree(perms[i]);
        kfree(perms);
-out:
        return rc;
 }
 
@@ -1635,34 +1624,27 @@ static int sel_make_class_dir_entries(char *classname, int index,
        int rc;
 
        dentry = d_alloc_name(dir, "index");
-       if (!dentry) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!dentry)
+               return -ENOMEM;
 
        inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
-       if (!inode) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!inode)
+               return -ENOMEM;
 
        inode->i_fop = &sel_class_ops;
        inode->i_ino = sel_class_to_ino(index);
        d_add(dentry, inode);
 
        dentry = d_alloc_name(dir, "perms");
-       if (!dentry) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!dentry)
+               return -ENOMEM;
 
        rc = sel_make_dir(dir->d_inode, dentry, &last_class_ino);
        if (rc)
-               goto out;
+               return rc;
 
        rc = sel_make_perm_files(classname, index, dentry);
 
-out:
        return rc;
 }
 
@@ -1692,15 +1674,15 @@ static void sel_remove_classes(void)
 
 static int sel_make_classes(void)
 {
-       int rc = 0, nclasses, i;
+       int rc, nclasses, i;
        char **classes;
 
        /* delete any existing entries */
        sel_remove_classes();
 
        rc = security_get_classes(&classes, &nclasses);
-       if (rc < 0)
-               goto out;
+       if (rc)
+               return rc;
 
        /* +2 since classes are 1-indexed */
        last_class_ino = sel_class_to_ino(nclasses + 2);
@@ -1708,29 +1690,27 @@ static int sel_make_classes(void)
        for (i = 0; i < nclasses; i++) {
                struct dentry *class_name_dir;
 
+               rc = -ENOMEM;
                class_name_dir = d_alloc_name(class_dir, classes[i]);
-               if (!class_name_dir) {
-                       rc = -ENOMEM;
-                       goto out1;
-               }
+               if (!class_name_dir)
+                       goto out;
 
                rc = sel_make_dir(class_dir->d_inode, class_name_dir,
                                &last_class_ino);
                if (rc)
-                       goto out1;
+                       goto out;
 
                /* i+1 since class values are 1-indexed */
                rc = sel_make_class_dir_entries(classes[i], i + 1,
                                class_name_dir);
                if (rc)
-                       goto out1;
+                       goto out;
        }
-
-out1:
+       rc = 0;
+out:
        for (i = 0; i < nclasses; i++)
                kfree(classes[i]);
        kfree(classes);
-out:
        return rc;
 }
 
@@ -1767,14 +1747,12 @@ static int sel_make_policycap(void)
 static int sel_make_dir(struct inode *dir, struct dentry *dentry,
                        unsigned long *ino)
 {
-       int ret = 0;
        struct inode *inode;
 
        inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO);
-       if (!inode) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!inode)
+               return -ENOMEM;
+
        inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
        inode->i_ino = ++(*ino);
@@ -1783,8 +1761,8 @@ static int sel_make_dir(struct inode *dir, struct dentry *dentry,
        d_add(dentry, inode);
        /* bump link count on parent directory, too */
        inc_nlink(dir);
-out:
-       return ret;
+
+       return 0;
 }
 
 static int sel_fill_super(struct super_block *sb, void *data, int silent)
@@ -1820,11 +1798,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
 
        root_inode = sb->s_root->d_inode;
 
+       ret = -ENOMEM;
        dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME);
-       if (!dentry) {
-               ret = -ENOMEM;
+       if (!dentry)
                goto err;
-       }
 
        ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
        if (ret)
@@ -1832,17 +1809,16 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
 
        bool_dir = dentry;
 
+       ret = -ENOMEM;
        dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
-       if (!dentry) {
-               ret = -ENOMEM;
+       if (!dentry)
                goto err;
-       }
 
+       ret = -ENOMEM;
        inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
-       if (!inode) {
-               ret = -ENOMEM;
+       if (!inode)
                goto err;
-       }
+
        inode->i_ino = ++sel_last_ino;
        isec = (struct inode_security_struct *)inode->i_security;
        isec->sid = SECINITSID_DEVNULL;
@@ -1853,11 +1829,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
        d_add(dentry, inode);
        selinux_null = dentry;
 
+       ret = -ENOMEM;
        dentry = d_alloc_name(sb->s_root, "avc");
-       if (!dentry) {
-               ret = -ENOMEM;
+       if (!dentry)
                goto err;
-       }
 
        ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
        if (ret)
@@ -1867,11 +1842,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
        if (ret)
                goto err;
 
+       ret = -ENOMEM;
        dentry = d_alloc_name(sb->s_root, "initial_contexts");
-       if (!dentry) {
-               ret = -ENOMEM;
+       if (!dentry)
                goto err;
-       }
 
        ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
        if (ret)
@@ -1881,11 +1855,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
        if (ret)
                goto err;
 
+       ret = -ENOMEM;
        dentry = d_alloc_name(sb->s_root, "class");
-       if (!dentry) {
-               ret = -ENOMEM;
+       if (!dentry)
                goto err;
-       }
 
        ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
        if (ret)
@@ -1893,11 +1866,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
 
        class_dir = dentry;
 
+       ret = -ENOMEM;
        dentry = d_alloc_name(sb->s_root, "policy_capabilities");
-       if (!dentry) {
-               ret = -ENOMEM;
+       if (!dentry)
                goto err;
-       }
 
        ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
        if (ret)
@@ -1905,12 +1877,11 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
 
        policycap_dir = dentry;
 
-out:
-       return ret;
+       return 0;
 err:
        printk(KERN_ERR "SELinux: %s:  failed while creating inodes\n",
                __func__);
-       goto out;
+       return ret;
 }
 
 static struct dentry *sel_mount(struct file_system_type *fs_type,
@@ -1934,14 +1905,16 @@ static int __init init_sel_fs(void)
        if (!selinux_enabled)
                return 0;
        err = register_filesystem(&sel_fs_type);
-       if (!err) {
-               selinuxfs_mount = kern_mount(&sel_fs_type);
-               if (IS_ERR(selinuxfs_mount)) {
-                       printk(KERN_ERR "selinuxfs:  could not mount!\n");
-                       err = PTR_ERR(selinuxfs_mount);
-                       selinuxfs_mount = NULL;
-               }
+       if (err)
+               return err;
+
+       selinuxfs_mount = kern_mount(&sel_fs_type);
+       if (IS_ERR(selinuxfs_mount)) {
+               printk(KERN_ERR "selinuxfs:  could not mount!\n");
+               err = PTR_ERR(selinuxfs_mount);
+               selinuxfs_mount = NULL;
        }
+
        return err;
 }
 
index 655fe1c6cc69dccd862b3142a37e41b6fb4010a7..c3f845cbcd48b6019dae5c3ca7df2bf4317a3b01 100644 (file)
@@ -193,6 +193,7 @@ int cond_index_bool(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct cond_bool_datum *booldatum;
+       struct flex_array *fa;
 
        booldatum = datum;
        p = datap;
@@ -200,7 +201,10 @@ int cond_index_bool(void *key, void *datum, void *datap)
        if (!booldatum->value || booldatum->value > p->p_bools.nprim)
                return -EINVAL;
 
-       p->p_bool_val_to_name[booldatum->value - 1] = key;
+       fa = p->sym_val_to_name[SYM_BOOLS];
+       if (flex_array_put_ptr(fa, booldatum->value - 1, key,
+                              GFP_KERNEL | __GFP_ZERO))
+               BUG();
        p->bool_val_to_struct[booldatum->value - 1] = booldatum;
 
        return 0;
index b4eff7a60c50b74e6ab46473551cf06c3c7541e2..1ef8e4e8988019881e880d7212f35398039acca0 100644 (file)
@@ -45,7 +45,7 @@ int mls_compute_context_len(struct context *context)
        len = 1; /* for the beginning ":" */
        for (l = 0; l < 2; l++) {
                int index_sens = context->range.level[l].sens;
-               len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
+               len += strlen(sym_name(&policydb, SYM_LEVELS, index_sens - 1));
 
                /* categories */
                head = -2;
@@ -55,17 +55,17 @@ int mls_compute_context_len(struct context *context)
                        if (i - prev > 1) {
                                /* one or more negative bits are skipped */
                                if (head != prev) {
-                                       nm = policydb.p_cat_val_to_name[prev];
+                                       nm = sym_name(&policydb, SYM_CATS, prev);
                                        len += strlen(nm) + 1;
                                }
-                               nm = policydb.p_cat_val_to_name[i];
+                               nm = sym_name(&policydb, SYM_CATS, i);
                                len += strlen(nm) + 1;
                                head = i;
                        }
                        prev = i;
                }
                if (prev != head) {
-                       nm = policydb.p_cat_val_to_name[prev];
+                       nm = sym_name(&policydb, SYM_CATS, prev);
                        len += strlen(nm) + 1;
                }
                if (l == 0) {
@@ -102,8 +102,8 @@ void mls_sid_to_context(struct context *context,
        scontextp++;
 
        for (l = 0; l < 2; l++) {
-               strcpy(scontextp,
-                      policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+               strcpy(scontextp, sym_name(&policydb, SYM_LEVELS,
+                                          context->range.level[l].sens - 1));
                scontextp += strlen(scontextp);
 
                /* categories */
@@ -118,7 +118,7 @@ void mls_sid_to_context(struct context *context,
                                                *scontextp++ = '.';
                                        else
                                                *scontextp++ = ',';
-                                       nm = policydb.p_cat_val_to_name[prev];
+                                       nm = sym_name(&policydb, SYM_CATS, prev);
                                        strcpy(scontextp, nm);
                                        scontextp += strlen(nm);
                                }
@@ -126,7 +126,7 @@ void mls_sid_to_context(struct context *context,
                                        *scontextp++ = ':';
                                else
                                        *scontextp++ = ',';
-                               nm = policydb.p_cat_val_to_name[i];
+                               nm = sym_name(&policydb, SYM_CATS, i);
                                strcpy(scontextp, nm);
                                scontextp += strlen(nm);
                                head = i;
@@ -139,7 +139,7 @@ void mls_sid_to_context(struct context *context,
                                *scontextp++ = '.';
                        else
                                *scontextp++ = ',';
-                       nm = policydb.p_cat_val_to_name[prev];
+                       nm = sym_name(&policydb, SYM_CATS, prev);
                        strcpy(scontextp, nm);
                        scontextp += strlen(nm);
                }
@@ -166,7 +166,7 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l)
        if (!l->sens || l->sens > p->p_levels.nprim)
                return 0;
        levdatum = hashtab_search(p->p_levels.table,
-                                 p->p_sens_val_to_name[l->sens - 1]);
+                                 sym_name(p, SYM_LEVELS, l->sens - 1));
        if (!levdatum)
                return 0;
 
@@ -482,7 +482,8 @@ int mls_convert_context(struct policydb *oldp,
 
        for (l = 0; l < 2; l++) {
                levdatum = hashtab_search(newp->p_levels.table,
-                       oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
+                                         sym_name(oldp, SYM_LEVELS,
+                                                  c->range.level[l].sens - 1));
 
                if (!levdatum)
                        return -EINVAL;
@@ -493,7 +494,7 @@ int mls_convert_context(struct policydb *oldp,
                        int rc;
 
                        catdatum = hashtab_search(newp->p_cats.table,
-                                                 oldp->p_cat_val_to_name[i]);
+                                                 sym_name(oldp, SYM_CATS, i));
                        if (!catdatum)
                                return -EINVAL;
                        rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
index 94f630d93a5c5d0964a51e030646d26652619ee6..be9de387283722607dc025fd52095c3fdf6f6883 100644 (file)
@@ -148,32 +148,30 @@ static int roles_init(struct policydb *p)
        int rc;
        struct role_datum *role;
 
+       rc = -ENOMEM;
        role = kzalloc(sizeof(*role), GFP_KERNEL);
-       if (!role) {
-               rc = -ENOMEM;
+       if (!role)
                goto out;
-       }
+
+       rc = -EINVAL;
        role->value = ++p->p_roles.nprim;
-       if (role->value != OBJECT_R_VAL) {
-               rc = -EINVAL;
-               goto out_free_role;
-       }
+       if (role->value != OBJECT_R_VAL)
+               goto out;
+
+       rc = -ENOMEM;
        key = kstrdup(OBJECT_R, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
-               goto out_free_role;
-       }
+       if (!key)
+               goto out;
+
        rc = hashtab_insert(p->p_roles.table, key, role);
        if (rc)
-               goto out_free_key;
-out:
-       return rc;
+               goto out;
 
-out_free_key:
+       return 0;
+out:
        kfree(key);
-out_free_role:
        kfree(role);
-       goto out;
+       return rc;
 }
 
 static u32 rangetr_hash(struct hashtab *h, const void *k)
@@ -213,35 +211,33 @@ static int policydb_init(struct policydb *p)
        for (i = 0; i < SYM_NUM; i++) {
                rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
                if (rc)
-                       goto out_free_symtab;
+                       goto out;
        }
 
        rc = avtab_init(&p->te_avtab);
        if (rc)
-               goto out_free_symtab;
+               goto out;
 
        rc = roles_init(p);
        if (rc)
-               goto out_free_symtab;
+               goto out;
 
        rc = cond_policydb_init(p);
        if (rc)
-               goto out_free_symtab;
+               goto out;
 
        p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
        if (!p->range_tr)
-               goto out_free_symtab;
+               goto out;
 
        ebitmap_init(&p->policycaps);
        ebitmap_init(&p->permissive_map);
 
+       return 0;
 out:
-       return rc;
-
-out_free_symtab:
        for (i = 0; i < SYM_NUM; i++)
                hashtab_destroy(p->symtab[i].table);
-       goto out;
+       return rc;
 }
 
 /*
@@ -258,12 +254,17 @@ static int common_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct common_datum *comdatum;
+       struct flex_array *fa;
 
        comdatum = datum;
        p = datap;
        if (!comdatum->value || comdatum->value > p->p_commons.nprim)
                return -EINVAL;
-       p->p_common_val_to_name[comdatum->value - 1] = key;
+
+       fa = p->sym_val_to_name[SYM_COMMONS];
+       if (flex_array_put_ptr(fa, comdatum->value - 1, key,
+                              GFP_KERNEL | __GFP_ZERO))
+               BUG();
        return 0;
 }
 
@@ -271,12 +272,16 @@ static int class_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct class_datum *cladatum;
+       struct flex_array *fa;
 
        cladatum = datum;
        p = datap;
        if (!cladatum->value || cladatum->value > p->p_classes.nprim)
                return -EINVAL;
-       p->p_class_val_to_name[cladatum->value - 1] = key;
+       fa = p->sym_val_to_name[SYM_CLASSES];
+       if (flex_array_put_ptr(fa, cladatum->value - 1, key,
+                              GFP_KERNEL | __GFP_ZERO))
+               BUG();
        p->class_val_to_struct[cladatum->value - 1] = cladatum;
        return 0;
 }
@@ -285,6 +290,7 @@ static int role_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct role_datum *role;
+       struct flex_array *fa;
 
        role = datum;
        p = datap;
@@ -292,7 +298,11 @@ static int role_index(void *key, void *datum, void *datap)
            || role->value > p->p_roles.nprim
            || role->bounds > p->p_roles.nprim)
                return -EINVAL;
-       p->p_role_val_to_name[role->value - 1] = key;
+
+       fa = p->sym_val_to_name[SYM_ROLES];
+       if (flex_array_put_ptr(fa, role->value - 1, key,
+                              GFP_KERNEL | __GFP_ZERO))
+               BUG();
        p->role_val_to_struct[role->value - 1] = role;
        return 0;
 }
@@ -301,6 +311,7 @@ static int type_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct type_datum *typdatum;
+       struct flex_array *fa;
 
        typdatum = datum;
        p = datap;
@@ -310,8 +321,15 @@ static int type_index(void *key, void *datum, void *datap)
                    || typdatum->value > p->p_types.nprim
                    || typdatum->bounds > p->p_types.nprim)
                        return -EINVAL;
-               p->p_type_val_to_name[typdatum->value - 1] = key;
-               p->type_val_to_struct[typdatum->value - 1] = typdatum;
+               fa = p->sym_val_to_name[SYM_TYPES];
+               if (flex_array_put_ptr(fa, typdatum->value - 1, key,
+                                      GFP_KERNEL | __GFP_ZERO))
+                       BUG();
+
+               fa = p->type_val_to_struct_array;
+               if (flex_array_put_ptr(fa, typdatum->value - 1, typdatum,
+                                      GFP_KERNEL | __GFP_ZERO))
+                       BUG();
        }
 
        return 0;
@@ -321,6 +339,7 @@ static int user_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct user_datum *usrdatum;
+       struct flex_array *fa;
 
        usrdatum = datum;
        p = datap;
@@ -328,7 +347,11 @@ static int user_index(void *key, void *datum, void *datap)
            || usrdatum->value > p->p_users.nprim
            || usrdatum->bounds > p->p_users.nprim)
                return -EINVAL;
-       p->p_user_val_to_name[usrdatum->value - 1] = key;
+
+       fa = p->sym_val_to_name[SYM_USERS];
+       if (flex_array_put_ptr(fa, usrdatum->value - 1, key,
+                              GFP_KERNEL | __GFP_ZERO))
+               BUG();
        p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
        return 0;
 }
@@ -337,6 +360,7 @@ static int sens_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct level_datum *levdatum;
+       struct flex_array *fa;
 
        levdatum = datum;
        p = datap;
@@ -345,7 +369,10 @@ static int sens_index(void *key, void *datum, void *datap)
                if (!levdatum->level->sens ||
                    levdatum->level->sens > p->p_levels.nprim)
                        return -EINVAL;
-               p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
+               fa = p->sym_val_to_name[SYM_LEVELS];
+               if (flex_array_put_ptr(fa, levdatum->level->sens - 1, key,
+                                      GFP_KERNEL | __GFP_ZERO))
+                       BUG();
        }
 
        return 0;
@@ -355,6 +382,7 @@ static int cat_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct cat_datum *catdatum;
+       struct flex_array *fa;
 
        catdatum = datum;
        p = datap;
@@ -362,7 +390,10 @@ static int cat_index(void *key, void *datum, void *datap)
        if (!catdatum->isalias) {
                if (!catdatum->value || catdatum->value > p->p_cats.nprim)
                        return -EINVAL;
-               p->p_cat_val_to_name[catdatum->value - 1] = key;
+               fa = p->sym_val_to_name[SYM_CATS];
+               if (flex_array_put_ptr(fa, catdatum->value - 1, key,
+                                      GFP_KERNEL | __GFP_ZERO))
+                       BUG();
        }
 
        return 0;
@@ -380,47 +411,6 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
        cat_index,
 };
 
-/*
- * Define the common val_to_name array and the class
- * val_to_name and val_to_struct arrays in a policy
- * database structure.
- *
- * Caller must clean up upon failure.
- */
-static int policydb_index_classes(struct policydb *p)
-{
-       int rc;
-
-       p->p_common_val_to_name =
-               kmalloc(p->p_commons.nprim * sizeof(char *), GFP_KERNEL);
-       if (!p->p_common_val_to_name) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       rc = hashtab_map(p->p_commons.table, common_index, p);
-       if (rc)
-               goto out;
-
-       p->class_val_to_struct =
-               kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), GFP_KERNEL);
-       if (!p->class_val_to_struct) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       p->p_class_val_to_name =
-               kmalloc(p->p_classes.nprim * sizeof(char *), GFP_KERNEL);
-       if (!p->p_class_val_to_name) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       rc = hashtab_map(p->p_classes.table, class_index, p);
-out:
-       return rc;
-}
-
 #ifdef DEBUG_HASHES
 static void symtab_hash_eval(struct symtab *s)
 {
@@ -458,9 +448,9 @@ static inline void rangetr_hash_eval(struct hashtab *h)
  *
  * Caller must clean up on failure.
  */
-static int policydb_index_others(struct policydb *p)
+static int policydb_index(struct policydb *p)
 {
-       int i, rc = 0;
+       int i, rc;
 
        printk(KERN_DEBUG "SELinux:  %d users, %d roles, %d types, %d bools",
               p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
@@ -477,47 +467,63 @@ static int policydb_index_others(struct policydb *p)
        symtab_hash_eval(p->symtab);
 #endif
 
+       rc = -ENOMEM;
+       p->class_val_to_struct =
+               kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)),
+                       GFP_KERNEL);
+       if (!p->class_val_to_struct)
+               goto out;
+
+       rc = -ENOMEM;
        p->role_val_to_struct =
                kmalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)),
                        GFP_KERNEL);
-       if (!p->role_val_to_struct) {
-               rc = -ENOMEM;
+       if (!p->role_val_to_struct)
                goto out;
-       }
 
+       rc = -ENOMEM;
        p->user_val_to_struct =
                kmalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)),
                        GFP_KERNEL);
-       if (!p->user_val_to_struct) {
-               rc = -ENOMEM;
+       if (!p->user_val_to_struct)
                goto out;
-       }
 
-       p->type_val_to_struct =
-               kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)),
-                       GFP_KERNEL);
-       if (!p->type_val_to_struct) {
-               rc = -ENOMEM;
+       /* Yes, I want the sizeof the pointer, not the structure */
+       rc = -ENOMEM;
+       p->type_val_to_struct_array = flex_array_alloc(sizeof(struct type_datum *),
+                                                      p->p_types.nprim,
+                                                      GFP_KERNEL | __GFP_ZERO);
+       if (!p->type_val_to_struct_array)
                goto out;
-       }
 
-       if (cond_init_bool_indexes(p)) {
-               rc = -ENOMEM;
+       rc = flex_array_prealloc(p->type_val_to_struct_array, 0,
+                                p->p_types.nprim - 1, GFP_KERNEL | __GFP_ZERO);
+       if (rc)
                goto out;
-       }
 
-       for (i = SYM_ROLES; i < SYM_NUM; i++) {
-               p->sym_val_to_name[i] =
-                       kmalloc(p->symtab[i].nprim * sizeof(char *), GFP_KERNEL);
-               if (!p->sym_val_to_name[i]) {
-                       rc = -ENOMEM;
+       rc = -ENOMEM;
+       if (cond_init_bool_indexes(p))
+               goto out;
+
+       for (i = 0; i < SYM_NUM; i++) {
+               rc = -ENOMEM;
+               p->sym_val_to_name[i] = flex_array_alloc(sizeof(char *),
+                                                        p->symtab[i].nprim,
+                                                        GFP_KERNEL | __GFP_ZERO);
+               if (!p->sym_val_to_name[i])
                        goto out;
-               }
+
+               rc = flex_array_prealloc(p->sym_val_to_name[i],
+                                        0, p->symtab[i].nprim - 1,
+                                        GFP_KERNEL | __GFP_ZERO);
+               if (rc)
+                       goto out;
+
                rc = hashtab_map(p->symtab[i].table, index_f[i], p);
                if (rc)
                        goto out;
        }
-
+       rc = 0;
 out:
        return rc;
 }
@@ -540,9 +546,11 @@ static int common_destroy(void *key, void *datum, void *p)
        struct common_datum *comdatum;
 
        kfree(key);
-       comdatum = datum;
-       hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
-       hashtab_destroy(comdatum->permissions.table);
+       if (datum) {
+               comdatum = datum;
+               hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
+               hashtab_destroy(comdatum->permissions.table);
+       }
        kfree(datum);
        return 0;
 }
@@ -554,38 +562,40 @@ static int cls_destroy(void *key, void *datum, void *p)
        struct constraint_expr *e, *etmp;
 
        kfree(key);
-       cladatum = datum;
-       hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
-       hashtab_destroy(cladatum->permissions.table);
-       constraint = cladatum->constraints;
-       while (constraint) {
-               e = constraint->expr;
-               while (e) {
-                       ebitmap_destroy(&e->names);
-                       etmp = e;
-                       e = e->next;
-                       kfree(etmp);
+       if (datum) {
+               cladatum = datum;
+               hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
+               hashtab_destroy(cladatum->permissions.table);
+               constraint = cladatum->constraints;
+               while (constraint) {
+                       e = constraint->expr;
+                       while (e) {
+                               ebitmap_destroy(&e->names);
+                               etmp = e;
+                               e = e->next;
+                               kfree(etmp);
+                       }
+                       ctemp = constraint;
+                       constraint = constraint->next;
+                       kfree(ctemp);
                }
-               ctemp = constraint;
-               constraint = constraint->next;
-               kfree(ctemp);
-       }
-
-       constraint = cladatum->validatetrans;
-       while (constraint) {
-               e = constraint->expr;
-               while (e) {
-                       ebitmap_destroy(&e->names);
-                       etmp = e;
-                       e = e->next;
-                       kfree(etmp);
+
+               constraint = cladatum->validatetrans;
+               while (constraint) {
+                       e = constraint->expr;
+                       while (e) {
+                               ebitmap_destroy(&e->names);
+                               etmp = e;
+                               e = e->next;
+                               kfree(etmp);
+                       }
+                       ctemp = constraint;
+                       constraint = constraint->next;
+                       kfree(ctemp);
                }
-               ctemp = constraint;
-               constraint = constraint->next;
-               kfree(ctemp);
-       }
 
-       kfree(cladatum->comkey);
+               kfree(cladatum->comkey);
+       }
        kfree(datum);
        return 0;
 }
@@ -595,9 +605,11 @@ static int role_destroy(void *key, void *datum, void *p)
        struct role_datum *role;
 
        kfree(key);
-       role = datum;
-       ebitmap_destroy(&role->dominates);
-       ebitmap_destroy(&role->types);
+       if (datum) {
+               role = datum;
+               ebitmap_destroy(&role->dominates);
+               ebitmap_destroy(&role->types);
+       }
        kfree(datum);
        return 0;
 }
@@ -614,11 +626,13 @@ static int user_destroy(void *key, void *datum, void *p)
        struct user_datum *usrdatum;
 
        kfree(key);
-       usrdatum = datum;
-       ebitmap_destroy(&usrdatum->roles);
-       ebitmap_destroy(&usrdatum->range.level[0].cat);
-       ebitmap_destroy(&usrdatum->range.level[1].cat);
-       ebitmap_destroy(&usrdatum->dfltlevel.cat);
+       if (datum) {
+               usrdatum = datum;
+               ebitmap_destroy(&usrdatum->roles);
+               ebitmap_destroy(&usrdatum->range.level[0].cat);
+               ebitmap_destroy(&usrdatum->range.level[1].cat);
+               ebitmap_destroy(&usrdatum->dfltlevel.cat);
+       }
        kfree(datum);
        return 0;
 }
@@ -628,9 +642,11 @@ static int sens_destroy(void *key, void *datum, void *p)
        struct level_datum *levdatum;
 
        kfree(key);
-       levdatum = datum;
-       ebitmap_destroy(&levdatum->level->cat);
-       kfree(levdatum->level);
+       if (datum) {
+               levdatum = datum;
+               ebitmap_destroy(&levdatum->level->cat);
+               kfree(levdatum->level);
+       }
        kfree(datum);
        return 0;
 }
@@ -695,13 +711,16 @@ void policydb_destroy(struct policydb *p)
                hashtab_destroy(p->symtab[i].table);
        }
 
-       for (i = 0; i < SYM_NUM; i++)
-               kfree(p->sym_val_to_name[i]);
+       for (i = 0; i < SYM_NUM; i++) {
+               if (p->sym_val_to_name[i])
+                       flex_array_free(p->sym_val_to_name[i]);
+       }
 
        kfree(p->class_val_to_struct);
        kfree(p->role_val_to_struct);
        kfree(p->user_val_to_struct);
-       kfree(p->type_val_to_struct);
+       if (p->type_val_to_struct_array)
+               flex_array_free(p->type_val_to_struct_array);
 
        avtab_destroy(&p->te_avtab);
 
@@ -785,19 +804,21 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
 
        head = p->ocontexts[OCON_ISID];
        for (c = head; c; c = c->next) {
+               rc = -EINVAL;
                if (!c->context[0].user) {
-                       printk(KERN_ERR "SELinux:  SID %s was never "
-                              "defined.\n", c->u.name);
-                       rc = -EINVAL;
+                       printk(KERN_ERR "SELinux:  SID %s was never defined.\n",
+                               c->u.name);
                        goto out;
                }
-               if (sidtab_insert(s, c->sid[0], &c->context[0])) {
-                       printk(KERN_ERR "SELinux:  unable to load initial "
-                              "SID %s.\n", c->u.name);
-                       rc = -EINVAL;
+
+               rc = sidtab_insert(s, c->sid[0], &c->context[0]);
+               if (rc) {
+                       printk(KERN_ERR "SELinux:  unable to load initial SID %s.\n",
+                               c->u.name);
                        goto out;
                }
        }
+       rc = 0;
 out:
        return rc;
 }
@@ -846,8 +867,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c)
                 * Role must be authorized for the type.
                 */
                role = p->role_val_to_struct[c->role - 1];
-               if (!ebitmap_get_bit(&role->types,
-                                    c->type - 1))
+               if (!ebitmap_get_bit(&role->types, c->type - 1))
                        /* role may not be associated with type */
                        return 0;
 
@@ -858,8 +878,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c)
                if (!usrdatum)
                        return 0;
 
-               if (!ebitmap_get_bit(&usrdatum->roles,
-                                    c->role - 1))
+               if (!ebitmap_get_bit(&usrdatum->roles, c->role - 1))
                        /* user may not be associated with role */
                        return 0;
        }
@@ -881,20 +900,22 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)
        int rc;
 
        rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
+       if (rc)
                goto out;
 
+       rc = -EINVAL;
        items = le32_to_cpu(buf[0]);
        if (items > ARRAY_SIZE(buf)) {
                printk(KERN_ERR "SELinux: mls:  range overflow\n");
-               rc = -EINVAL;
                goto out;
        }
+
        rc = next_entry(buf, fp, sizeof(u32) * items);
-       if (rc < 0) {
+       if (rc) {
                printk(KERN_ERR "SELinux: mls:  truncated range\n");
                goto out;
        }
+
        r->level[0].sens = le32_to_cpu(buf[0]);
        if (items > 1)
                r->level[1].sens = le32_to_cpu(buf[1]);
@@ -903,15 +924,13 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)
 
        rc = ebitmap_read(&r->level[0].cat, fp);
        if (rc) {
-               printk(KERN_ERR "SELinux: mls:  error reading low "
-                      "categories\n");
+               printk(KERN_ERR "SELinux: mls:  error reading low categories\n");
                goto out;
        }
        if (items > 1) {
                rc = ebitmap_read(&r->level[1].cat, fp);
                if (rc) {
-                       printk(KERN_ERR "SELinux: mls:  error reading high "
-                              "categories\n");
+                       printk(KERN_ERR "SELinux: mls:  error reading high categories\n");
                        goto bad_high;
                }
        } else {
@@ -922,12 +941,11 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)
                }
        }
 
-       rc = 0;
-out:
-       return rc;
+       return 0;
 bad_high:
        ebitmap_destroy(&r->level[0].cat);
-       goto out;
+out:
+       return rc;
 }
 
 /*
@@ -942,7 +960,7 @@ static int context_read_and_validate(struct context *c,
        int rc;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0) {
+       if (rc) {
                printk(KERN_ERR "SELinux: context truncated\n");
                goto out;
        }
@@ -950,19 +968,20 @@ static int context_read_and_validate(struct context *c,
        c->role = le32_to_cpu(buf[1]);
        c->type = le32_to_cpu(buf[2]);
        if (p->policyvers >= POLICYDB_VERSION_MLS) {
-               if (mls_read_range_helper(&c->range, fp)) {
-                       printk(KERN_ERR "SELinux: error reading MLS range of "
-                              "context\n");
-                       rc = -EINVAL;
+               rc = mls_read_range_helper(&c->range, fp);
+               if (rc) {
+                       printk(KERN_ERR "SELinux: error reading MLS range of context\n");
                        goto out;
                }
        }
 
+       rc = -EINVAL;
        if (!policydb_context_isvalid(p, c)) {
                printk(KERN_ERR "SELinux:  invalid security context\n");
                context_destroy(c);
-               rc = -EINVAL;
+               goto out;
        }
+       rc = 0;
 out:
        return rc;
 }
@@ -981,37 +1000,36 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[2];
        u32 len;
 
+       rc = -ENOMEM;
        perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL);
-       if (!perdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!perdatum)
+               goto bad;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
        perdatum->value = le32_to_cpu(buf[1]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
+
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
        rc = hashtab_insert(h, key, perdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
+
+       return 0;
 bad:
        perm_destroy(key, perdatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int common_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1022,14 +1040,13 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
        u32 len, nel;
        int i, rc;
 
+       rc = -ENOMEM;
        comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL);
-       if (!comdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!comdatum)
+               goto bad;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
@@ -1041,13 +1058,13 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
        comdatum->permissions.nprim = le32_to_cpu(buf[2]);
        nel = le32_to_cpu(buf[3]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
+
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
@@ -1060,11 +1077,10 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = hashtab_insert(h, key, comdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
+       return 0;
 bad:
        common_destroy(key, comdatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int read_cons_helper(struct constraint_node **nodep, int ncons,
@@ -1088,7 +1104,7 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
                        *nodep = c;
 
                rc = next_entry(buf, fp, (sizeof(u32) * 2));
-               if (rc < 0)
+               if (rc)
                        return rc;
                c->permissions = le32_to_cpu(buf[0]);
                nexpr = le32_to_cpu(buf[1]);
@@ -1105,7 +1121,7 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
                                c->expr = e;
 
                        rc = next_entry(buf, fp, (sizeof(u32) * 3));
-                       if (rc < 0)
+                       if (rc)
                                return rc;
                        e->expr_type = le32_to_cpu(buf[0]);
                        e->attr = le32_to_cpu(buf[1]);
@@ -1133,8 +1149,9 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
                                if (depth == (CEXPR_MAXDEPTH - 1))
                                        return -EINVAL;
                                depth++;
-                               if (ebitmap_read(&e->names, fp))
-                                       return -EINVAL;
+                               rc = ebitmap_read(&e->names, fp);
+                               if (rc)
+                                       return rc;
                                break;
                        default:
                                return -EINVAL;
@@ -1157,14 +1174,13 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
        u32 len, len2, ncons, nel;
        int i, rc;
 
+       rc = -ENOMEM;
        cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL);
-       if (!cladatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!cladatum)
+               goto bad;
 
        rc = next_entry(buf, fp, sizeof(u32)*6);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
@@ -1179,33 +1195,30 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
 
        ncons = le32_to_cpu(buf[5]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
+
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
        if (len2) {
+               rc = -ENOMEM;
                cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL);
-               if (!cladatum->comkey) {
-                       rc = -ENOMEM;
+               if (!cladatum->comkey)
                        goto bad;
-               }
                rc = next_entry(cladatum->comkey, fp, len2);
-               if (rc < 0)
+               if (rc)
                        goto bad;
                cladatum->comkey[len2] = '\0';
 
-               cladatum->comdatum = hashtab_search(p->p_commons.table,
-                                                   cladatum->comkey);
+               rc = -EINVAL;
+               cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey);
                if (!cladatum->comdatum) {
-                       printk(KERN_ERR "SELinux:  unknown common %s\n",
-                              cladatum->comkey);
-                       rc = -EINVAL;
+                       printk(KERN_ERR "SELinux:  unknown common %s\n", cladatum->comkey);
                        goto bad;
                }
        }
@@ -1222,7 +1235,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
        if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) {
                /* grab the validatetrans rules */
                rc = next_entry(buf, fp, sizeof(u32));
-               if (rc < 0)
+               if (rc)
                        goto bad;
                ncons = le32_to_cpu(buf[0]);
                rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
@@ -1234,12 +1247,10 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
        if (rc)
                goto bad;
 
-       rc = 0;
-out:
-       return rc;
+       return 0;
 bad:
        cls_destroy(key, cladatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int role_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1250,17 +1261,16 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[3];
        u32 len;
 
+       rc = -ENOMEM;
        role = kzalloc(sizeof(*role), GFP_KERNEL);
-       if (!role) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!role)
+               goto bad;
 
        if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
                to_read = 3;
 
        rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
@@ -1268,13 +1278,13 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
        if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
                role->bounds = le32_to_cpu(buf[2]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
+
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
@@ -1287,10 +1297,10 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
                goto bad;
 
        if (strcmp(key, OBJECT_R) == 0) {
+               rc = -EINVAL;
                if (role->value != OBJECT_R_VAL) {
                        printk(KERN_ERR "SELinux: Role %s has wrong value %d\n",
                               OBJECT_R, role->value);
-                       rc = -EINVAL;
                        goto bad;
                }
                rc = 0;
@@ -1300,11 +1310,10 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = hashtab_insert(h, key, role);
        if (rc)
                goto bad;
-out:
-       return rc;
+       return 0;
 bad:
        role_destroy(key, role, NULL);
-       goto out;
+       return rc;
 }
 
 static int type_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1315,17 +1324,16 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[4];
        u32 len;
 
+       rc = -ENOMEM;
        typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
-       if (!typdatum) {
-               rc = -ENOMEM;
-               return rc;
-       }
+       if (!typdatum)
+               goto bad;
 
        if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
                to_read = 4;
 
        rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
@@ -1343,24 +1351,22 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
                typdatum->primary = le32_to_cpu(buf[2]);
        }
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
        rc = hashtab_insert(h, key, typdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
+       return 0;
 bad:
        type_destroy(key, typdatum, NULL);
-       goto out;
+       return rc;
 }
 
 
@@ -1376,22 +1382,18 @@ static int mls_read_level(struct mls_level *lp, void *fp)
        memset(lp, 0, sizeof(*lp));
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0) {
+       if (rc) {
                printk(KERN_ERR "SELinux: mls: truncated level\n");
-               goto bad;
+               return rc;
        }
        lp->sens = le32_to_cpu(buf[0]);
 
-       if (ebitmap_read(&lp->cat, fp)) {
-               printk(KERN_ERR "SELinux: mls:  error reading level "
-                      "categories\n");
-               goto bad;
+       rc = ebitmap_read(&lp->cat, fp);
+       if (rc) {
+               printk(KERN_ERR "SELinux: mls:  error reading level categories\n");
+               return rc;
        }
-
        return 0;
-
-bad:
-       return -EINVAL;
 }
 
 static int user_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1402,17 +1404,16 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[3];
        u32 len;
 
+       rc = -ENOMEM;
        usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
-       if (!usrdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!usrdatum)
+               goto bad;
 
        if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
                to_read = 3;
 
        rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
@@ -1420,13 +1421,12 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
        if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
                usrdatum->bounds = le32_to_cpu(buf[2]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
@@ -1446,11 +1446,10 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = hashtab_insert(h, key, usrdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
+       return 0;
 bad:
        user_destroy(key, usrdatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1461,47 +1460,43 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[2];
        u32 len;
 
+       rc = -ENOMEM;
        levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC);
-       if (!levdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!levdatum)
+               goto bad;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
        levdatum->isalias = le32_to_cpu(buf[1]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_ATOMIC);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
+       rc = -ENOMEM;
        levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC);
-       if (!levdatum->level) {
-               rc = -ENOMEM;
+       if (!levdatum->level)
                goto bad;
-       }
-       if (mls_read_level(levdatum->level, fp)) {
-               rc = -EINVAL;
+
+       rc = mls_read_level(levdatum->level, fp);
+       if (rc)
                goto bad;
-       }
 
        rc = hashtab_insert(h, key, levdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
+       return 0;
 bad:
        sens_destroy(key, levdatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1512,39 +1507,35 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[3];
        u32 len;
 
+       rc = -ENOMEM;
        catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC);
-       if (!catdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!catdatum)
+               goto bad;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
        catdatum->value = le32_to_cpu(buf[1]);
        catdatum->isalias = le32_to_cpu(buf[2]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_ATOMIC);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
        rc = hashtab_insert(h, key, catdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
-
+       return 0;
 bad:
        cat_destroy(key, catdatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) =
@@ -1585,9 +1576,9 @@ static int user_bounds_sanity_check(void *key, void *datum, void *datap)
                        printk(KERN_ERR
                               "SELinux: boundary violated policy: "
                               "user=%s role=%s bounds=%s\n",
-                              p->p_user_val_to_name[user->value - 1],
-                              p->p_role_val_to_name[bit],
-                              p->p_user_val_to_name[upper->value - 1]);
+                              sym_name(p, SYM_USERS, user->value - 1),
+                              sym_name(p, SYM_ROLES, bit),
+                              sym_name(p, SYM_USERS, upper->value - 1));
 
                        return -EINVAL;
                }
@@ -1622,9 +1613,9 @@ static int role_bounds_sanity_check(void *key, void *datum, void *datap)
                        printk(KERN_ERR
                               "SELinux: boundary violated policy: "
                               "role=%s type=%s bounds=%s\n",
-                              p->p_role_val_to_name[role->value - 1],
-                              p->p_type_val_to_name[bit],
-                              p->p_role_val_to_name[upper->value - 1]);
+                              sym_name(p, SYM_ROLES, role->value - 1),
+                              sym_name(p, SYM_TYPES, bit),
+                              sym_name(p, SYM_ROLES, upper->value - 1));
 
                        return -EINVAL;
                }
@@ -1648,12 +1639,15 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap)
                        return -EINVAL;
                }
 
-               upper = p->type_val_to_struct[upper->bounds - 1];
+               upper = flex_array_get_ptr(p->type_val_to_struct_array,
+                                          upper->bounds - 1);
+               BUG_ON(!upper);
+
                if (upper->attribute) {
                        printk(KERN_ERR "SELinux: type %s: "
                               "bounded by attribute %s",
                               (char *) key,
-                              p->p_type_val_to_name[upper->value - 1]);
+                              sym_name(p, SYM_TYPES, upper->value - 1));
                        return -EINVAL;
                }
        }
@@ -2066,13 +2060,14 @@ int policydb_read(struct policydb *p, void *fp)
 
        rc = policydb_init(p);
        if (rc)
-               goto out;
+               return rc;
 
        /* Read the magic number and string length. */
        rc = next_entry(buf, fp, sizeof(u32) * 2);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
+       rc = -EINVAL;
        if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) {
                printk(KERN_ERR "SELinux:  policydb magic number 0x%x does "
                       "not match expected magic number 0x%x\n",
@@ -2080,6 +2075,7 @@ int policydb_read(struct policydb *p, void *fp)
                goto bad;
        }
 
+       rc = -EINVAL;
        len = le32_to_cpu(buf[1]);
        if (len != strlen(POLICYDB_STRING)) {
                printk(KERN_ERR "SELinux:  policydb string length %d does not "
@@ -2087,19 +2083,23 @@ int policydb_read(struct policydb *p, void *fp)
                       len, strlen(POLICYDB_STRING));
                goto bad;
        }
+
+       rc = -ENOMEM;
        policydb_str = kmalloc(len + 1, GFP_KERNEL);
        if (!policydb_str) {
                printk(KERN_ERR "SELinux:  unable to allocate memory for policydb "
                       "string of length %d\n", len);
-               rc = -ENOMEM;
                goto bad;
        }
+
        rc = next_entry(policydb_str, fp, len);
-       if (rc < 0) {
+       if (rc) {
                printk(KERN_ERR "SELinux:  truncated policydb string identifier\n");
                kfree(policydb_str);
                goto bad;
        }
+
+       rc = -EINVAL;
        policydb_str[len] = '\0';
        if (strcmp(policydb_str, POLICYDB_STRING)) {
                printk(KERN_ERR "SELinux:  policydb string %s does not match "
@@ -2113,9 +2113,10 @@ int policydb_read(struct policydb *p, void *fp)
 
        /* Read the version and table sizes. */
        rc = next_entry(buf, fp, sizeof(u32)*4);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
+       rc = -EINVAL;
        p->policyvers = le32_to_cpu(buf[0]);
        if (p->policyvers < POLICYDB_VERSION_MIN ||
            p->policyvers > POLICYDB_VERSION_MAX) {
@@ -2128,6 +2129,7 @@ int policydb_read(struct policydb *p, void *fp)
        if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
                p->mls_enabled = 1;
 
+               rc = -EINVAL;
                if (p->policyvers < POLICYDB_VERSION_MLS) {
                        printk(KERN_ERR "SELinux: security policydb version %d "
                                "(MLS) not backwards compatible\n",
@@ -2138,14 +2140,19 @@ int policydb_read(struct policydb *p, void *fp)
        p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
        p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
 
-       if (p->policyvers >= POLICYDB_VERSION_POLCAP &&
-           ebitmap_read(&p->policycaps, fp) != 0)
-               goto bad;
+       if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
+               rc = ebitmap_read(&p->policycaps, fp);
+               if (rc)
+                       goto bad;
+       }
 
-       if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
-           ebitmap_read(&p->permissive_map, fp) != 0)
-               goto bad;
+       if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) {
+               rc = ebitmap_read(&p->permissive_map, fp);
+               if (rc)
+                       goto bad;
+       }
 
+       rc = -EINVAL;
        info = policydb_lookup_compat(p->policyvers);
        if (!info) {
                printk(KERN_ERR "SELinux:  unable to find policy compat info "
@@ -2153,6 +2160,7 @@ int policydb_read(struct policydb *p, void *fp)
                goto bad;
        }
 
+       rc = -EINVAL;
        if (le32_to_cpu(buf[2]) != info->sym_num ||
                le32_to_cpu(buf[3]) != info->ocon_num) {
                printk(KERN_ERR "SELinux:  policydb table sizes (%d,%d) do "
@@ -2164,7 +2172,7 @@ int policydb_read(struct policydb *p, void *fp)
 
        for (i = 0; i < info->sym_num; i++) {
                rc = next_entry(buf, fp, sizeof(u32)*2);
-               if (rc < 0)
+               if (rc)
                        goto bad;
                nprim = le32_to_cpu(buf[0]);
                nel = le32_to_cpu(buf[1]);
@@ -2188,78 +2196,73 @@ int policydb_read(struct policydb *p, void *fp)
        }
 
        rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
+       if (rc)
                goto bad;
        nel = le32_to_cpu(buf[0]);
        ltr = NULL;
        for (i = 0; i < nel; i++) {
+               rc = -ENOMEM;
                tr = kzalloc(sizeof(*tr), GFP_KERNEL);
-               if (!tr) {
-                       rc = -ENOMEM;
+               if (!tr)
                        goto bad;
-               }
                if (ltr)
                        ltr->next = tr;
                else
                        p->role_tr = tr;
                rc = next_entry(buf, fp, sizeof(u32)*3);
-               if (rc < 0)
+               if (rc)
                        goto bad;
+
+               rc = -EINVAL;
                tr->role = le32_to_cpu(buf[0]);
                tr->type = le32_to_cpu(buf[1]);
                tr->new_role = le32_to_cpu(buf[2]);
                if (!policydb_role_isvalid(p, tr->role) ||
                    !policydb_type_isvalid(p, tr->type) ||
-                   !policydb_role_isvalid(p, tr->new_role)) {
-                       rc = -EINVAL;
+                   !policydb_role_isvalid(p, tr->new_role))
                        goto bad;
-               }
                ltr = tr;
        }
 
        rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
+       if (rc)
                goto bad;
        nel = le32_to_cpu(buf[0]);
        lra = NULL;
        for (i = 0; i < nel; i++) {
+               rc = -ENOMEM;
                ra = kzalloc(sizeof(*ra), GFP_KERNEL);
-               if (!ra) {
-                       rc = -ENOMEM;
+               if (!ra)
                        goto bad;
-               }
                if (lra)
                        lra->next = ra;
                else
                        p->role_allow = ra;
                rc = next_entry(buf, fp, sizeof(u32)*2);
-               if (rc < 0)
+               if (rc)
                        goto bad;
+
+               rc = -EINVAL;
                ra->role = le32_to_cpu(buf[0]);
                ra->new_role = le32_to_cpu(buf[1]);
                if (!policydb_role_isvalid(p, ra->role) ||
-                   !policydb_role_isvalid(p, ra->new_role)) {
-                       rc = -EINVAL;
+                   !policydb_role_isvalid(p, ra->new_role))
                        goto bad;
-               }
                lra = ra;
        }
 
-       rc = policydb_index_classes(p);
-       if (rc)
-               goto bad;
-
-       rc = policydb_index_others(p);
+       rc = policydb_index(p);
        if (rc)
                goto bad;
 
+       rc = -EINVAL;
        p->process_class = string_to_security_class(p, "process");
        if (!p->process_class)
                goto bad;
-       p->process_trans_perms = string_to_av_perm(p, p->process_class,
-                                                  "transition");
-       p->process_trans_perms |= string_to_av_perm(p, p->process_class,
-                                                   "dyntransition");
+
+       rc = -EINVAL;
+       p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition");
+       p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition");
        if (!p->process_trans_perms)
                goto bad;
 
@@ -2312,8 +2315,6 @@ int policydb_read(struct policydb *p, void *fp)
 out:
        return rc;
 bad:
-       if (!rc)
-               rc = -EINVAL;
        policydb_destroy(p);
        goto out;
 }
@@ -3076,7 +3077,7 @@ int policydb_write(struct policydb *p, void *fp)
        if (!info) {
                printk(KERN_ERR "SELinux: compatibility lookup failed for policy "
                    "version %d", p->policyvers);
-               return rc;
+               return -EINVAL;
        }
 
        buf[0] = cpu_to_le32(p->policyvers);
index 95d3d7de361e628adcc53b974533cafb384ef851..4e3ab9d0b315032a6e267072424c476aa5cd2048 100644 (file)
@@ -203,21 +203,13 @@ struct policydb {
 #define p_cats symtab[SYM_CATS]
 
        /* symbol names indexed by (value - 1) */
-       char **sym_val_to_name[SYM_NUM];
-#define p_common_val_to_name sym_val_to_name[SYM_COMMONS]
-#define p_class_val_to_name sym_val_to_name[SYM_CLASSES]
-#define p_role_val_to_name sym_val_to_name[SYM_ROLES]
-#define p_type_val_to_name sym_val_to_name[SYM_TYPES]
-#define p_user_val_to_name sym_val_to_name[SYM_USERS]
-#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
-#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
-#define p_cat_val_to_name sym_val_to_name[SYM_CATS]
+       struct flex_array *sym_val_to_name[SYM_NUM];
 
        /* class, role, and user attributes indexed by (value - 1) */
        struct class_datum **class_val_to_struct;
        struct role_datum **role_val_to_struct;
        struct user_datum **user_val_to_struct;
-       struct type_datum **type_val_to_struct;
+       struct flex_array *type_val_to_struct_array;
 
        /* type enforcement access vectors and transitions */
        struct avtab te_avtab;
@@ -321,6 +313,13 @@ static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file
        return 0;
 }
 
+static inline char *sym_name(struct policydb *p, unsigned int sym_num, unsigned int element_nr)
+{
+       struct flex_array *fa = p->sym_val_to_name[sym_num];
+
+       return flex_array_get_ptr(fa, element_nr);
+}
+
 extern u16 string_to_security_class(struct policydb *p, const char *name);
 extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name);
 
index 223c1ff6ef2324488eca915d2ba87bc4f6e27fa9..a03cfaf0ee078d03771a90f6e2e50d46b9d55db7 100644 (file)
@@ -464,7 +464,7 @@ static void security_dump_masked_av(struct context *scontext,
        if (!permissions)
                return;
 
-       tclass_name = policydb.p_class_val_to_name[tclass - 1];
+       tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1);
        tclass_dat = policydb.class_val_to_struct[tclass - 1];
        common_dat = tclass_dat->comdatum;
 
@@ -530,12 +530,18 @@ static void type_attribute_bounds_av(struct context *scontext,
        struct context lo_scontext;
        struct context lo_tcontext;
        struct av_decision lo_avd;
-       struct type_datum *source
-               = policydb.type_val_to_struct[scontext->type - 1];
-       struct type_datum *target
-               = policydb.type_val_to_struct[tcontext->type - 1];
+       struct type_datum *source;
+       struct type_datum *target;
        u32 masked = 0;
 
+       source = flex_array_get_ptr(policydb.type_val_to_struct_array,
+                                   scontext->type - 1);
+       BUG_ON(!source);
+
+       target = flex_array_get_ptr(policydb.type_val_to_struct_array,
+                                   tcontext->type - 1);
+       BUG_ON(!target);
+
        if (source->bounds) {
                memset(&lo_avd, 0, sizeof(lo_avd));
 
@@ -701,16 +707,16 @@ static int security_validtrans_handle_fail(struct context *ocontext,
        char *o = NULL, *n = NULL, *t = NULL;
        u32 olen, nlen, tlen;
 
-       if (context_struct_to_string(ocontext, &o, &olen) < 0)
+       if (context_struct_to_string(ocontext, &o, &olen))
                goto out;
-       if (context_struct_to_string(ncontext, &n, &nlen) < 0)
+       if (context_struct_to_string(ncontext, &n, &nlen))
                goto out;
-       if (context_struct_to_string(tcontext, &t, &tlen) < 0)
+       if (context_struct_to_string(tcontext, &t, &tlen))
                goto out;
        audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
                  "security_validate_transition:  denied for"
                  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
-                 o, n, t, policydb.p_class_val_to_name[tclass-1]);
+                 o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
 out:
        kfree(o);
        kfree(n);
@@ -801,10 +807,11 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
        struct context *old_context, *new_context;
        struct type_datum *type;
        int index;
-       int rc = -EINVAL;
+       int rc;
 
        read_lock(&policy_rwlock);
 
+       rc = -EINVAL;
        old_context = sidtab_search(&sidtab, old_sid);
        if (!old_context) {
                printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
@@ -812,6 +819,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
                goto out;
        }
 
+       rc = -EINVAL;
        new_context = sidtab_search(&sidtab, new_sid);
        if (!new_context) {
                printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
@@ -819,28 +827,27 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
                goto out;
        }
 
+       rc = 0;
        /* type/domain unchanged */
-       if (old_context->type == new_context->type) {
-               rc = 0;
+       if (old_context->type == new_context->type)
                goto out;
-       }
 
        index = new_context->type;
        while (true) {
-               type = policydb.type_val_to_struct[index - 1];
+               type = flex_array_get_ptr(policydb.type_val_to_struct_array,
+                                         index - 1);
                BUG_ON(!type);
 
                /* not bounded anymore */
-               if (!type->bounds) {
-                       rc = -EPERM;
+               rc = -EPERM;
+               if (!type->bounds)
                        break;
-               }
 
                /* @newsid is bounded by @oldsid */
-               if (type->bounds == old_context->type) {
-                       rc = 0;
+               rc = 0;
+               if (type->bounds == old_context->type)
                        break;
-               }
+
                index = type->bounds;
        }
 
@@ -1005,9 +1012,9 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
        }
 
        /* Compute the size of the context. */
-       *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1;
-       *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1;
-       *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
+       *scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1;
+       *scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1;
+       *scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1;
        *scontext_len += mls_compute_context_len(context);
 
        if (!scontext)
@@ -1023,12 +1030,12 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
         * Copy the user name, role name and type name into the context.
         */
        sprintf(scontextp, "%s:%s:%s",
-               policydb.p_user_val_to_name[context->user - 1],
-               policydb.p_role_val_to_name[context->role - 1],
-               policydb.p_type_val_to_name[context->type - 1]);
-       scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) +
-                    1 + strlen(policydb.p_role_val_to_name[context->role - 1]) +
-                    1 + strlen(policydb.p_type_val_to_name[context->type - 1]);
+               sym_name(&policydb, SYM_USERS, context->user - 1),
+               sym_name(&policydb, SYM_ROLES, context->role - 1),
+               sym_name(&policydb, SYM_TYPES, context->type - 1));
+       scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) +
+                    1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) +
+                    1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1));
 
        mls_sid_to_context(context, &scontextp);
 
@@ -1187,16 +1194,13 @@ static int string_to_context_struct(struct policydb *pol,
        if (rc)
                goto out;
 
-       if ((p - scontext) < scontext_len) {
-               rc = -EINVAL;
+       rc = -EINVAL;
+       if ((p - scontext) < scontext_len)
                goto out;
-       }
 
        /* Check the validity of the new context. */
-       if (!policydb_context_isvalid(pol, ctx)) {
-               rc = -EINVAL;
+       if (!policydb_context_isvalid(pol, ctx))
                goto out;
-       }
        rc = 0;
 out:
        if (rc)
@@ -1235,27 +1239,26 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
 
        if (force) {
                /* Save another copy for storing in uninterpreted form */
+               rc = -ENOMEM;
                str = kstrdup(scontext2, gfp_flags);
-               if (!str) {
-                       kfree(scontext2);
-                       return -ENOMEM;
-               }
+               if (!str)
+                       goto out;
        }
 
        read_lock(&policy_rwlock);
-       rc = string_to_context_struct(&policydb, &sidtab,
-                                     scontext2, scontext_len,
-                                     &context, def_sid);
+       rc = string_to_context_struct(&policydb, &sidtab, scontext2,
+                                     scontext_len, &context, def_sid);
        if (rc == -EINVAL && force) {
                context.str = str;
                context.len = scontext_len;
                str = NULL;
        } else if (rc)
-               goto out;
+               goto out_unlock;
        rc = sidtab_context_to_sid(&sidtab, &context, sid);
        context_destroy(&context);
-out:
+out_unlock:
        read_unlock(&policy_rwlock);
+out:
        kfree(scontext2);
        kfree(str);
        return rc;
@@ -1319,18 +1322,18 @@ static int compute_sid_handle_invalid_context(
        char *s = NULL, *t = NULL, *n = NULL;
        u32 slen, tlen, nlen;
 
-       if (context_struct_to_string(scontext, &s, &slen) < 0)
+       if (context_struct_to_string(scontext, &s, &slen))
                goto out;
-       if (context_struct_to_string(tcontext, &t, &tlen) < 0)
+       if (context_struct_to_string(tcontext, &t, &tlen))
                goto out;
-       if (context_struct_to_string(newcontext, &n, &nlen) < 0)
+       if (context_struct_to_string(newcontext, &n, &nlen))
                goto out;
        audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
                  "security_compute_sid:  invalid context %s"
                  " for scontext=%s"
                  " tcontext=%s"
                  " tclass=%s",
-                 n, s, t, policydb.p_class_val_to_name[tclass-1]);
+                 n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
 out:
        kfree(s);
        kfree(t);
@@ -1569,22 +1572,17 @@ static int clone_sid(u32 sid,
 
 static inline int convert_context_handle_invalid_context(struct context *context)
 {
-       int rc = 0;
+       char *s;
+       u32 len;
 
-       if (selinux_enforcing) {
-               rc = -EINVAL;
-       } else {
-               char *s;
-               u32 len;
-
-               if (!context_struct_to_string(context, &s, &len)) {
-                       printk(KERN_WARNING
-                      "SELinux:  Context %s would be invalid if enforcing\n",
-                              s);
-                       kfree(s);
-               }
+       if (selinux_enforcing)
+               return -EINVAL;
+
+       if (!context_struct_to_string(context, &s, &len)) {
+               printk(KERN_WARNING "SELinux:  Context %s would be invalid if enforcing\n", s);
+               kfree(s);
        }
-       return rc;
+       return 0;
 }
 
 struct convert_context_args {
@@ -1621,17 +1619,17 @@ static int convert_context(u32 key,
 
        if (c->str) {
                struct context ctx;
+
+               rc = -ENOMEM;
                s = kstrdup(c->str, GFP_KERNEL);
-               if (!s) {
-                       rc = -ENOMEM;
+               if (!s)
                        goto out;
-               }
+
                rc = string_to_context_struct(args->newp, NULL, s,
                                              c->len, &ctx, SECSID_NULL);
                kfree(s);
                if (!rc) {
-                       printk(KERN_INFO
-                      "SELinux:  Context %s became valid (mapped).\n",
+                       printk(KERN_INFO "SELinux:  Context %s became valid (mapped).\n",
                               c->str);
                        /* Replace string with mapped representation. */
                        kfree(c->str);
@@ -1643,8 +1641,7 @@ static int convert_context(u32 key,
                        goto out;
                } else {
                        /* Other error condition, e.g. ENOMEM. */
-                       printk(KERN_ERR
-                      "SELinux:   Unable to map context %s, rc = %d.\n",
+                       printk(KERN_ERR "SELinux:   Unable to map context %s, rc = %d.\n",
                               c->str, -rc);
                        goto out;
                }
@@ -1654,25 +1651,26 @@ static int convert_context(u32 key,
        if (rc)
                goto out;
 
-       rc = -EINVAL;
-
        /* Convert the user. */
+       rc = -EINVAL;
        usrdatum = hashtab_search(args->newp->p_users.table,
-                                 args->oldp->p_user_val_to_name[c->user - 1]);
+                                 sym_name(args->oldp, SYM_USERS, c->user - 1));
        if (!usrdatum)
                goto bad;
        c->user = usrdatum->value;
 
        /* Convert the role. */
+       rc = -EINVAL;
        role = hashtab_search(args->newp->p_roles.table,
-                             args->oldp->p_role_val_to_name[c->role - 1]);
+                             sym_name(args->oldp, SYM_ROLES, c->role - 1));
        if (!role)
                goto bad;
        c->role = role->value;
 
        /* Convert the type. */
+       rc = -EINVAL;
        typdatum = hashtab_search(args->newp->p_types.table,
-                                 args->oldp->p_type_val_to_name[c->type - 1]);
+                                 sym_name(args->oldp, SYM_TYPES, c->type - 1));
        if (!typdatum)
                goto bad;
        c->type = typdatum->value;
@@ -1700,6 +1698,7 @@ static int convert_context(u32 key,
                oc = args->newp->ocontexts[OCON_ISID];
                while (oc && oc->sid[0] != SECINITSID_UNLABELED)
                        oc = oc->next;
+               rc = -EINVAL;
                if (!oc) {
                        printk(KERN_ERR "SELinux:  unable to look up"
                                " the initial SIDs list\n");
@@ -1719,19 +1718,20 @@ static int convert_context(u32 key,
        }
 
        context_destroy(&oldc);
+
        rc = 0;
 out:
        return rc;
 bad:
        /* Map old representation to string and save it. */
-       if (context_struct_to_string(&oldc, &s, &len))
-               return -ENOMEM;
+       rc = context_struct_to_string(&oldc, &s, &len);
+       if (rc)
+               return rc;
        context_destroy(&oldc);
        context_destroy(c);
        c->str = s;
        c->len = len;
-       printk(KERN_INFO
-              "SELinux:  Context %s became invalid (unmapped).\n",
+       printk(KERN_INFO "SELinux:  Context %s became invalid (unmapped).\n",
               c->str);
        rc = 0;
        goto out;
@@ -2012,7 +2012,7 @@ int security_node_sid(u16 domain,
                      u32 addrlen,
                      u32 *out_sid)
 {
-       int rc = 0;
+       int rc;
        struct ocontext *c;
 
        read_lock(&policy_rwlock);
@@ -2021,10 +2021,9 @@ int security_node_sid(u16 domain,
        case AF_INET: {
                u32 addr;
 
-               if (addrlen != sizeof(u32)) {
-                       rc = -EINVAL;
+               rc = -EINVAL;
+               if (addrlen != sizeof(u32))
                        goto out;
-               }
 
                addr = *((u32 *)addrp);
 
@@ -2038,10 +2037,9 @@ int security_node_sid(u16 domain,
        }
 
        case AF_INET6:
-               if (addrlen != sizeof(u64) * 2) {
-                       rc = -EINVAL;
+               rc = -EINVAL;
+               if (addrlen != sizeof(u64) * 2)
                        goto out;
-               }
                c = policydb.ocontexts[OCON_NODE6];
                while (c) {
                        if (match_ipv6_addrmask(addrp, c->u.node6.addr,
@@ -2052,6 +2050,7 @@ int security_node_sid(u16 domain,
                break;
 
        default:
+               rc = 0;
                *out_sid = SECINITSID_NODE;
                goto out;
        }
@@ -2069,6 +2068,7 @@ int security_node_sid(u16 domain,
                *out_sid = SECINITSID_NODE;
        }
 
+       rc = 0;
 out:
        read_unlock(&policy_rwlock);
        return rc;
@@ -2113,24 +2113,22 @@ int security_get_user_sids(u32 fromsid,
 
        context_init(&usercon);
 
+       rc = -EINVAL;
        fromcon = sidtab_search(&sidtab, fromsid);
-       if (!fromcon) {
-               rc = -EINVAL;
+       if (!fromcon)
                goto out_unlock;
-       }
 
+       rc = -EINVAL;
        user = hashtab_search(policydb.p_users.table, username);
-       if (!user) {
-               rc = -EINVAL;
+       if (!user)
                goto out_unlock;
-       }
+
        usercon.user = user->value;
 
+       rc = -ENOMEM;
        mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
-       if (!mysids) {
-               rc = -ENOMEM;
+       if (!mysids)
                goto out_unlock;
-       }
 
        ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
                role = policydb.role_val_to_struct[i];
@@ -2147,12 +2145,11 @@ int security_get_user_sids(u32 fromsid,
                        if (mynel < maxnel) {
                                mysids[mynel++] = sid;
                        } else {
+                               rc = -ENOMEM;
                                maxnel += SIDS_NEL;
                                mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
-                               if (!mysids2) {
-                                       rc = -ENOMEM;
+                               if (!mysids2)
                                        goto out_unlock;
-                               }
                                memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
                                kfree(mysids);
                                mysids = mysids2;
@@ -2160,7 +2157,7 @@ int security_get_user_sids(u32 fromsid,
                        }
                }
        }
-
+       rc = 0;
 out_unlock:
        read_unlock(&policy_rwlock);
        if (rc || !mynel) {
@@ -2168,9 +2165,9 @@ out_unlock:
                goto out;
        }
 
+       rc = -ENOMEM;
        mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
        if (!mysids2) {
-               rc = -ENOMEM;
                kfree(mysids);
                goto out;
        }
@@ -2211,7 +2208,7 @@ int security_genfs_sid(const char *fstype,
        u16 sclass;
        struct genfs *genfs;
        struct ocontext *c;
-       int rc = 0, cmp = 0;
+       int rc, cmp = 0;
 
        while (path[0] == '/' && path[1] == '/')
                path++;
@@ -2219,6 +2216,7 @@ int security_genfs_sid(const char *fstype,
        read_lock(&policy_rwlock);
 
        sclass = unmap_class(orig_sclass);
+       *sid = SECINITSID_UNLABELED;
 
        for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
                cmp = strcmp(fstype, genfs->fstype);
@@ -2226,11 +2224,9 @@ int security_genfs_sid(const char *fstype,
                        break;
        }
 
-       if (!genfs || cmp) {
-               *sid = SECINITSID_UNLABELED;
-               rc = -ENOENT;
+       rc = -ENOENT;
+       if (!genfs || cmp)
                goto out;
-       }
 
        for (c = genfs->head; c; c = c->next) {
                len = strlen(c->u.name);
@@ -2239,21 +2235,18 @@ int security_genfs_sid(const char *fstype,
                        break;
        }
 
-       if (!c) {
-               *sid = SECINITSID_UNLABELED;
-               rc = -ENOENT;
+       rc = -ENOENT;
+       if (!c)
                goto out;
-       }
 
        if (!c->sid[0]) {
-               rc = sidtab_context_to_sid(&sidtab,
-                                          &c->context[0],
-                                          &c->sid[0]);
+               rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
                if (rc)
                        goto out;
        }
 
        *sid = c->sid[0];
+       rc = 0;
 out:
        read_unlock(&policy_rwlock);
        return rc;
@@ -2285,8 +2278,7 @@ int security_fs_use(
        if (c) {
                *behavior = c->v.behavior;
                if (!c->sid[0]) {
-                       rc = sidtab_context_to_sid(&sidtab,
-                                                  &c->context[0],
+                       rc = sidtab_context_to_sid(&sidtab, &c->context[0],
                                                   &c->sid[0]);
                        if (rc)
                                goto out;
@@ -2309,34 +2301,39 @@ out:
 
 int security_get_bools(int *len, char ***names, int **values)
 {
-       int i, rc = -ENOMEM;
+       int i, rc;
 
        read_lock(&policy_rwlock);
        *names = NULL;
        *values = NULL;
 
+       rc = 0;
        *len = policydb.p_bools.nprim;
-       if (!*len) {
-               rc = 0;
+       if (!*len)
                goto out;
-       }
 
-       *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
+       rc = -ENOMEM;
+       *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
        if (!*names)
                goto err;
 
-       *values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
+       rc = -ENOMEM;
+       *values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
        if (!*values)
                goto err;
 
        for (i = 0; i < *len; i++) {
                size_t name_len;
+
                (*values)[i] = policydb.bool_val_to_struct[i]->state;
-               name_len = strlen(policydb.p_bool_val_to_name[i]) + 1;
-              (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
+               name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1;
+
+               rc = -ENOMEM;
+               (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
                if (!(*names)[i])
                        goto err;
-               strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len);
+
+               strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len);
                (*names)[i][name_len - 1] = 0;
        }
        rc = 0;
@@ -2355,24 +2352,23 @@ err:
 
 int security_set_bools(int len, int *values)
 {
-       int i, rc = 0;
+       int i, rc;
        int lenp, seqno = 0;
        struct cond_node *cur;
 
        write_lock_irq(&policy_rwlock);
 
+       rc = -EFAULT;
        lenp = policydb.p_bools.nprim;
-       if (len != lenp) {
-               rc = -EFAULT;
+       if (len != lenp)
                goto out;
-       }
 
        for (i = 0; i < len; i++) {
                if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
                        audit_log(current->audit_context, GFP_ATOMIC,
                                AUDIT_MAC_CONFIG_CHANGE,
                                "bool=%s val=%d old_val=%d auid=%u ses=%u",
-                               policydb.p_bool_val_to_name[i],
+                               sym_name(&policydb, SYM_BOOLS, i),
                                !!values[i],
                                policydb.bool_val_to_struct[i]->state,
                                audit_get_loginuid(current),
@@ -2391,7 +2387,7 @@ int security_set_bools(int len, int *values)
        }
 
        seqno = ++latest_granting;
-
+       rc = 0;
 out:
        write_unlock_irq(&policy_rwlock);
        if (!rc) {
@@ -2405,16 +2401,15 @@ out:
 
 int security_get_bool_value(int bool)
 {
-       int rc = 0;
+       int rc;
        int len;
 
        read_lock(&policy_rwlock);
 
+       rc = -EFAULT;
        len = policydb.p_bools.nprim;
-       if (bool >= len) {
-               rc = -EFAULT;
+       if (bool >= len)
                goto out;
-       }
 
        rc = policydb.bool_val_to_struct[bool]->state;
 out:
@@ -2464,8 +2459,9 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
        struct context newcon;
        char *s;
        u32 len;
-       int rc = 0;
+       int rc;
 
+       rc = 0;
        if (!ss_initialized || !policydb.mls_enabled) {
                *new_sid = sid;
                goto out;
@@ -2474,19 +2470,20 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
        context_init(&newcon);
 
        read_lock(&policy_rwlock);
+
+       rc = -EINVAL;
        context1 = sidtab_search(&sidtab, sid);
        if (!context1) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                        __func__, sid);
-               rc = -EINVAL;
                goto out_unlock;
        }
 
+       rc = -EINVAL;
        context2 = sidtab_search(&sidtab, mls_sid);
        if (!context2) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                        __func__, mls_sid);
-               rc = -EINVAL;
                goto out_unlock;
        }
 
@@ -2500,20 +2497,17 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
        /* Check the validity of the new context. */
        if (!policydb_context_isvalid(&policydb, &newcon)) {
                rc = convert_context_handle_invalid_context(&newcon);
-               if (rc)
-                       goto bad;
+               if (rc) {
+                       if (!context_struct_to_string(&newcon, &s, &len)) {
+                               audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+                                         "security_sid_mls_copy: invalid context %s", s);
+                               kfree(s);
+                       }
+                       goto out_unlock;
+               }
        }
 
        rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid);
-       goto out_unlock;
-
-bad:
-       if (!context_struct_to_string(&newcon, &s, &len)) {
-               audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                         "security_sid_mls_copy: invalid context %s", s);
-               kfree(s);
-       }
-
 out_unlock:
        read_unlock(&policy_rwlock);
        context_destroy(&newcon);
@@ -2549,6 +2543,8 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
        struct context *nlbl_ctx;
        struct context *xfrm_ctx;
 
+       *peer_sid = SECSID_NULL;
+
        /* handle the common (which also happens to be the set of easy) cases
         * right away, these two if statements catch everything involving a
         * single or absent peer SID/label */
@@ -2567,40 +2563,37 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
        /* we don't need to check ss_initialized here since the only way both
         * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
         * security server was initialized and ss_initialized was true */
-       if (!policydb.mls_enabled) {
-               *peer_sid = SECSID_NULL;
+       if (!policydb.mls_enabled)
                return 0;
-       }
 
        read_lock(&policy_rwlock);
 
+       rc = -EINVAL;
        nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
        if (!nlbl_ctx) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                       __func__, nlbl_sid);
-               rc = -EINVAL;
-               goto out_slowpath;
+               goto out;
        }
+       rc = -EINVAL;
        xfrm_ctx = sidtab_search(&sidtab, xfrm_sid);
        if (!xfrm_ctx) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                       __func__, xfrm_sid);
-               rc = -EINVAL;
-               goto out_slowpath;
+               goto out;
        }
        rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
+       if (rc)
+               goto out;
 
-out_slowpath:
+       /* at present NetLabel SIDs/labels really only carry MLS
+        * information so if the MLS portion of the NetLabel SID
+        * matches the MLS portion of the labeled XFRM SID/label
+        * then pass along the XFRM SID as it is the most
+        * expressive */
+       *peer_sid = xfrm_sid;
+out:
        read_unlock(&policy_rwlock);
-       if (rc == 0)
-               /* at present NetLabel SIDs/labels really only carry MLS
-                * information so if the MLS portion of the NetLabel SID
-                * matches the MLS portion of the labeled XFRM SID/label
-                * then pass along the XFRM SID as it is the most
-                * expressive */
-               *peer_sid = xfrm_sid;
-       else
-               *peer_sid = SECSID_NULL;
        return rc;
 }
 
@@ -2619,10 +2612,11 @@ static int get_classes_callback(void *k, void *d, void *args)
 
 int security_get_classes(char ***classes, int *nclasses)
 {
-       int rc = -ENOMEM;
+       int rc;
 
        read_lock(&policy_rwlock);
 
+       rc = -ENOMEM;
        *nclasses = policydb.p_classes.nprim;
        *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
        if (!*classes)
@@ -2630,7 +2624,7 @@ int security_get_classes(char ***classes, int *nclasses)
 
        rc = hashtab_map(policydb.p_classes.table, get_classes_callback,
                        *classes);
-       if (rc < 0) {
+       if (rc) {
                int i;
                for (i = 0; i < *nclasses; i++)
                        kfree((*classes)[i]);
@@ -2657,19 +2651,20 @@ static int get_permissions_callback(void *k, void *d, void *args)
 
 int security_get_permissions(char *class, char ***perms, int *nperms)
 {
-       int rc = -ENOMEM, i;
+       int rc, i;
        struct class_datum *match;
 
        read_lock(&policy_rwlock);
 
+       rc = -EINVAL;
        match = hashtab_search(policydb.p_classes.table, class);
        if (!match) {
                printk(KERN_ERR "SELinux: %s:  unrecognized class %s\n",
                        __func__, class);
-               rc = -EINVAL;
                goto out;
        }
 
+       rc = -ENOMEM;
        *nperms = match->permissions.nprim;
        *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
        if (!*perms)
@@ -2678,13 +2673,13 @@ int security_get_permissions(char *class, char ***perms, int *nperms)
        if (match->comdatum) {
                rc = hashtab_map(match->comdatum->permissions.table,
                                get_permissions_callback, *perms);
-               if (rc < 0)
+               if (rc)
                        goto err;
        }
 
        rc = hashtab_map(match->permissions.table, get_permissions_callback,
                        *perms);
-       if (rc < 0)
+       if (rc)
                goto err;
 
 out:
@@ -2796,36 +2791,39 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
        switch (field) {
        case AUDIT_SUBJ_USER:
        case AUDIT_OBJ_USER:
+               rc = -EINVAL;
                userdatum = hashtab_search(policydb.p_users.table, rulestr);
                if (!userdatum)
-                       rc = -EINVAL;
-               else
-                       tmprule->au_ctxt.user = userdatum->value;
+                       goto out;
+               tmprule->au_ctxt.user = userdatum->value;
                break;
        case AUDIT_SUBJ_ROLE:
        case AUDIT_OBJ_ROLE:
+               rc = -EINVAL;
                roledatum = hashtab_search(policydb.p_roles.table, rulestr);
                if (!roledatum)
-                       rc = -EINVAL;
-               else
-                       tmprule->au_ctxt.role = roledatum->value;
+                       goto out;
+               tmprule->au_ctxt.role = roledatum->value;
                break;
        case AUDIT_SUBJ_TYPE:
        case AUDIT_OBJ_TYPE:
+               rc = -EINVAL;
                typedatum = hashtab_search(policydb.p_types.table, rulestr);
                if (!typedatum)
-                       rc = -EINVAL;
-               else
-                       tmprule->au_ctxt.type = typedatum->value;
+                       goto out;
+               tmprule->au_ctxt.type = typedatum->value;
                break;
        case AUDIT_SUBJ_SEN:
        case AUDIT_SUBJ_CLR:
        case AUDIT_OBJ_LEV_LOW:
        case AUDIT_OBJ_LEV_HIGH:
                rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
+               if (rc)
+                       goto out;
                break;
        }
-
+       rc = 0;
+out:
        read_unlock(&policy_rwlock);
 
        if (rc) {
@@ -3050,7 +3048,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
 int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
                                   u32 *sid)
 {
-       int rc = -EIDRM;
+       int rc;
        struct context *ctx;
        struct context ctx_new;
 
@@ -3061,16 +3059,15 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
 
        read_lock(&policy_rwlock);
 
-       if (secattr->flags & NETLBL_SECATTR_CACHE) {
+       if (secattr->flags & NETLBL_SECATTR_CACHE)
                *sid = *(u32 *)secattr->cache->data;
-               rc = 0;
-       } else if (secattr->flags & NETLBL_SECATTR_SECID) {
+       else if (secattr->flags & NETLBL_SECATTR_SECID)
                *sid = secattr->attr.secid;
-               rc = 0;
-       } else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
+       else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
+               rc = -EIDRM;
                ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
                if (ctx == NULL)
-                       goto netlbl_secattr_to_sid_return;
+                       goto out;
 
                context_init(&ctx_new);
                ctx_new.user = ctx->user;
@@ -3078,34 +3075,35 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
                ctx_new.type = ctx->type;
                mls_import_netlbl_lvl(&ctx_new, secattr);
                if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
-                       if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
-                                                 secattr->attr.mls.cat) != 0)
-                               goto netlbl_secattr_to_sid_return;
+                       rc = ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
+                                                  secattr->attr.mls.cat);
+                       if (rc)
+                               goto out;
                        memcpy(&ctx_new.range.level[1].cat,
                               &ctx_new.range.level[0].cat,
                               sizeof(ctx_new.range.level[0].cat));
                }
-               if (mls_context_isvalid(&policydb, &ctx_new) != 1)
-                       goto netlbl_secattr_to_sid_return_cleanup;
+               rc = -EIDRM;
+               if (!mls_context_isvalid(&policydb, &ctx_new))
+                       goto out_free;
 
                rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
-               if (rc != 0)
-                       goto netlbl_secattr_to_sid_return_cleanup;
+               if (rc)
+                       goto out_free;
 
                security_netlbl_cache_add(secattr, *sid);
 
                ebitmap_destroy(&ctx_new.range.level[0].cat);
-       } else {
+       } else
                *sid = SECSID_NULL;
-               rc = 0;
-       }
 
-netlbl_secattr_to_sid_return:
        read_unlock(&policy_rwlock);
-       return rc;
-netlbl_secattr_to_sid_return_cleanup:
+       return 0;
+out_free:
        ebitmap_destroy(&ctx_new.range.level[0].cat);
-       goto netlbl_secattr_to_sid_return;
+out:
+       read_unlock(&policy_rwlock);
+       return rc;
 }
 
 /**
@@ -3127,28 +3125,23 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
                return 0;
 
        read_lock(&policy_rwlock);
+
+       rc = -ENOENT;
        ctx = sidtab_search(&sidtab, sid);
-       if (ctx == NULL) {
-               rc = -ENOENT;
-               goto netlbl_sid_to_secattr_failure;
-       }
-       secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
+       if (ctx == NULL)
+               goto out;
+
+       rc = -ENOMEM;
+       secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1),
                                  GFP_ATOMIC);
-       if (secattr->domain == NULL) {
-               rc = -ENOMEM;
-               goto netlbl_sid_to_secattr_failure;
-       }
+       if (secattr->domain == NULL)
+               goto out;
+
        secattr->attr.secid = sid;
        secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
        mls_export_netlbl_lvl(ctx, secattr);
        rc = mls_export_netlbl_cat(ctx, secattr);
-       if (rc != 0)
-               goto netlbl_sid_to_secattr_failure;
-       read_unlock(&policy_rwlock);
-
-       return 0;
-
-netlbl_sid_to_secattr_failure:
+out:
        read_unlock(&policy_rwlock);
        return rc;
 }
index e817989764cd48dd4061bc49c30c6cb8da357474..5840a35155fc3d613ec10abceee8420c1b40073f 100644 (file)
@@ -147,6 +147,17 @@ out:
        return rc;
 }
 
+static void sidtab_update_cache(struct sidtab *s, struct sidtab_node *n, int loc)
+{
+       BUG_ON(loc >= SIDTAB_CACHE_LEN);
+
+       while (loc > 0) {
+               s->cache[loc] = s->cache[loc - 1];
+               loc--;
+       }
+       s->cache[0] = n;
+}
+
 static inline u32 sidtab_search_context(struct sidtab *s,
                                                  struct context *context)
 {
@@ -156,14 +167,33 @@ static inline u32 sidtab_search_context(struct sidtab *s,
        for (i = 0; i < SIDTAB_SIZE; i++) {
                cur = s->htable[i];
                while (cur) {
-                       if (context_cmp(&cur->context, context))
+                       if (context_cmp(&cur->context, context)) {
+                               sidtab_update_cache(s, cur, SIDTAB_CACHE_LEN - 1);
                                return cur->sid;
+                       }
                        cur = cur->next;
                }
        }
        return 0;
 }
 
+static inline u32 sidtab_search_cache(struct sidtab *s, struct context *context)
+{
+       int i;
+       struct sidtab_node *node;
+
+       for (i = 0; i < SIDTAB_CACHE_LEN; i++) {
+               node = s->cache[i];
+               if (unlikely(!node))
+                       return 0;
+               if (context_cmp(&node->context, context)) {
+                       sidtab_update_cache(s, node, i);
+                       return node->sid;
+               }
+       }
+       return 0;
+}
+
 int sidtab_context_to_sid(struct sidtab *s,
                          struct context *context,
                          u32 *out_sid)
@@ -174,7 +204,9 @@ int sidtab_context_to_sid(struct sidtab *s,
 
        *out_sid = SECSID_NULL;
 
-       sid = sidtab_search_context(s, context);
+       sid  = sidtab_search_cache(s, context);
+       if (!sid)
+               sid = sidtab_search_context(s, context);
        if (!sid) {
                spin_lock_irqsave(&s->lock, flags);
                /* Rescan now that we hold the lock. */
@@ -259,12 +291,15 @@ void sidtab_destroy(struct sidtab *s)
 void sidtab_set(struct sidtab *dst, struct sidtab *src)
 {
        unsigned long flags;
+       int i;
 
        spin_lock_irqsave(&src->lock, flags);
        dst->htable = src->htable;
        dst->nel = src->nel;
        dst->next_sid = src->next_sid;
        dst->shutdown = 0;
+       for (i = 0; i < SIDTAB_CACHE_LEN; i++)
+               dst->cache[i] = NULL;
        spin_unlock_irqrestore(&src->lock, flags);
 }
 
index 64ea5b1cdea4775908a871e9c728aed6be5e3e30..84dc154d9389db3b6353443e7c6d3c1997e08a76 100644 (file)
@@ -26,6 +26,8 @@ struct sidtab {
        unsigned int nel;       /* number of elements */
        unsigned int next_sid;  /* next SID to allocate */
        unsigned char shutdown;
+#define SIDTAB_CACHE_LEN       3
+       struct sidtab_node *cache[SIDTAB_CACHE_LEN];
        spinlock_t lock;
 };
 
index 43ae747a5aa4e60746fdc7cdb15ec5cd3bb42b52..129c4eb8ffb10cbba9dce59ef4e5761624d19f7e 100644 (file)
@@ -51,11 +51,18 @@ struct socket_smack {
  */
 struct inode_smack {
        char            *smk_inode;     /* label of the fso */
+       char            *smk_task;      /* label of the task */
        struct mutex    smk_lock;       /* initialization lock */
        int             smk_flags;      /* smack inode flags */
 };
 
+struct task_smack {
+       char            *smk_task;      /* label used for access control */
+       char            *smk_forked;    /* label when forked */
+};
+
 #define        SMK_INODE_INSTANT       0x01    /* inode is instantiated */
+#define        SMK_INODE_TRANSMUTE     0x02    /* directory is transmuting */
 
 /*
  * A label access rule.
@@ -160,6 +167,10 @@ struct smack_known {
 #define SMACK_CIPSO_MAXLEVEL            255     /* CIPSO 2.2 standard */
 #define SMACK_CIPSO_MAXCATNUM           239     /* CIPSO 2.2 standard */
 
+/*
+ * Flag for transmute access
+ */
+#define MAY_TRANSMUTE  64
 /*
  * Just to make the common cases easier to deal with
  */
@@ -191,6 +202,7 @@ struct inode_smack *new_inode_smack(char *);
 /*
  * These functions are in smack_access.c
  */
+int smk_access_entry(char *, char *);
 int smk_access(char *, char *, int, struct smk_audit_info *);
 int smk_curacc(char *, u32, struct smk_audit_info *);
 int smack_to_cipso(const char *, struct smack_cipso *);
@@ -233,6 +245,15 @@ static inline void smack_catset_bit(int cat, char *catsetp)
        catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8);
 }
 
+/*
+ * Is the directory transmuting?
+ */
+static inline int smk_inode_transmutable(const struct inode *isp)
+{
+       struct inode_smack *sip = isp->i_security;
+       return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0;
+}
+
 /*
  * Present a pointer to the smack label in an inode blob.
  */
@@ -242,6 +263,30 @@ static inline char *smk_of_inode(const struct inode *isp)
        return sip->smk_inode;
 }
 
+/*
+ * Present a pointer to the smack label in an task blob.
+ */
+static inline char *smk_of_task(const struct task_smack *tsp)
+{
+       return tsp->smk_task;
+}
+
+/*
+ * Present a pointer to the forked smack label in an task blob.
+ */
+static inline char *smk_of_forked(const struct task_smack *tsp)
+{
+       return tsp->smk_forked;
+}
+
+/*
+ * Present a pointer to the smack label in the current task blob.
+ */
+static inline char *smk_of_current(void)
+{
+       return smk_of_task(current_security());
+}
+
 /*
  * logging functions
  */
index f4fac64c4da8b153aef2d4cb817d31348bab4110..7ba8478f599e9c0b2e6ae01c88fa4dd0340c2c27 100644 (file)
@@ -66,6 +66,46 @@ static u32 smack_next_secid = 10;
  */
 int log_policy = SMACK_AUDIT_DENIED;
 
+/**
+ * smk_access_entry - look up matching access rule
+ * @subject_label: a pointer to the subject's Smack label
+ * @object_label: a pointer to the object's Smack label
+ *
+ * This function looks up the subject/object pair in the
+ * access rule list and returns pointer to the matching rule if found,
+ * NULL otherwise.
+ *
+ * NOTE:
+ * Even though Smack labels are usually shared on smack_list
+ * labels that come in off the network can't be imported
+ * and added to the list for locking reasons.
+ *
+ * Therefore, it is necessary to check the contents of the labels,
+ * not just the pointer values. Of course, in most cases the labels
+ * will be on the list, so checking the pointers may be a worthwhile
+ * optimization.
+ */
+int smk_access_entry(char *subject_label, char *object_label)
+{
+       u32 may = MAY_NOT;
+       struct smack_rule *srp;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(srp, &smack_rule_list, list) {
+               if (srp->smk_subject == subject_label ||
+                   strcmp(srp->smk_subject, subject_label) == 0) {
+                       if (srp->smk_object == object_label ||
+                           strcmp(srp->smk_object, object_label) == 0) {
+                               may = srp->smk_access;
+                               break;
+                       }
+               }
+       }
+       rcu_read_unlock();
+
+       return may;
+}
+
 /**
  * smk_access - determine if a subject has a specific access to an object
  * @subject_label: a pointer to the subject's Smack label
@@ -90,7 +130,6 @@ int smk_access(char *subject_label, char *object_label, int request,
               struct smk_audit_info *a)
 {
        u32 may = MAY_NOT;
-       struct smack_rule *srp;
        int rc = 0;
 
        /*
@@ -144,18 +183,7 @@ int smk_access(char *subject_label, char *object_label, int request,
         * access (e.g. read is included in readwrite) it's
         * good.
         */
-       rcu_read_lock();
-       list_for_each_entry_rcu(srp, &smack_rule_list, list) {
-               if (srp->smk_subject == subject_label ||
-                   strcmp(srp->smk_subject, subject_label) == 0) {
-                       if (srp->smk_object == object_label ||
-                           strcmp(srp->smk_object, object_label) == 0) {
-                               may = srp->smk_access;
-                               break;
-                       }
-               }
-       }
-       rcu_read_unlock();
+       may = smk_access_entry(subject_label, object_label);
        /*
         * This is a bit map operation.
         */
@@ -185,7 +213,7 @@ out_audit:
 int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
 {
        int rc;
-       char *sp = current_security();
+       char *sp = smk_of_current();
 
        rc = smk_access(sp, obj_label, mode, NULL);
        if (rc == 0)
@@ -196,7 +224,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
         * only one that gets privilege and current does not
         * have that label.
         */
-       if (smack_onlycap != NULL && smack_onlycap != current->cred->security)
+       if (smack_onlycap != NULL && smack_onlycap != sp)
                goto out_audit;
 
        if (capable(CAP_MAC_OVERRIDE))
index ccb71a044a1aed408255dde1f2e79dbc42c852f0..533bf3255d7fde4d2f1ca2e0989e23b4a919f225 100644 (file)
@@ -3,12 +3,14 @@
  *
  *  This file contains the smack hook function implementations.
  *
- *  Author:
+ *  Authors:
  *     Casey Schaufler <casey@schaufler-ca.com>
+ *     Jarkko Sakkinen <ext-jarkko.2.sakkinen@nokia.com>
  *
  *  Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
  *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  *                Paul Moore <paul.moore@hp.com>
+ *  Copyright (C) 2010 Nokia Corporation
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License version 2,
@@ -35,6 +37,9 @@
 
 #define task_security(task)    (task_cred_xxx((task), security))
 
+#define TRANS_TRUE     "TRUE"
+#define TRANS_TRUE_SIZE        4
+
 /**
  * smk_fetch - Fetch the smack label from a file.
  * @ip: a pointer to the inode
@@ -43,7 +48,7 @@
  * Returns a pointer to the master list entry for the Smack label
  * or NULL if there was no label to fetch.
  */
-static char *smk_fetch(struct inode *ip, struct dentry *dp)
+static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)
 {
        int rc;
        char in[SMK_LABELLEN];
@@ -51,7 +56,7 @@ static char *smk_fetch(struct inode *ip, struct dentry *dp)
        if (ip->i_op->getxattr == NULL)
                return NULL;
 
-       rc = ip->i_op->getxattr(dp, XATTR_NAME_SMACK, in, SMK_LABELLEN);
+       rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN);
        if (rc < 0)
                return NULL;
 
@@ -103,8 +108,8 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
        if (rc != 0)
                return rc;
 
-       sp = current_security();
-       tsp = task_security(ctp);
+       sp = smk_of_current();
+       tsp = smk_of_task(task_security(ctp));
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, ctp);
 
@@ -138,8 +143,8 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, ptp);
 
-       sp = current_security();
-       tsp = task_security(ptp);
+       sp = smk_of_current();
+       tsp = smk_of_task(task_security(ptp));
        /* we won't log here, because rc can be overriden */
        rc = smk_access(tsp, sp, MAY_READWRITE, NULL);
        if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE))
@@ -160,7 +165,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
 static int smack_syslog(int typefrom_file)
 {
        int rc = 0;
-       char *sp = current_security();
+       char *sp = smk_of_current();
 
        if (capable(CAP_MAC_OVERRIDE))
                return 0;
@@ -390,6 +395,40 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
        return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
 }
 
+/*
+ * BPRM hooks
+ */
+
+static int smack_bprm_set_creds(struct linux_binprm *bprm)
+{
+       struct task_smack *tsp = bprm->cred->security;
+       struct inode_smack *isp;
+       struct dentry *dp;
+       int rc;
+
+       rc = cap_bprm_set_creds(bprm);
+       if (rc != 0)
+               return rc;
+
+       if (bprm->cred_prepared)
+               return 0;
+
+       if (bprm->file == NULL || bprm->file->f_dentry == NULL)
+               return 0;
+
+       dp = bprm->file->f_dentry;
+
+       if (dp->d_inode == NULL)
+               return 0;
+
+       isp = dp->d_inode->i_security;
+
+       if (isp->smk_task != NULL)
+               tsp->smk_task = isp->smk_task;
+
+       return 0;
+}
+
 /*
  * Inode hooks
  */
@@ -402,7 +441,7 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
  */
 static int smack_inode_alloc_security(struct inode *inode)
 {
-       inode->i_security = new_inode_smack(current_security());
+       inode->i_security = new_inode_smack(smk_of_current());
        if (inode->i_security == NULL)
                return -ENOMEM;
        return 0;
@@ -434,6 +473,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
                                     char **name, void **value, size_t *len)
 {
        char *isp = smk_of_inode(inode);
+       char *dsp = smk_of_inode(dir);
+       u32 may;
 
        if (name) {
                *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL);
@@ -442,6 +483,16 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
        }
 
        if (value) {
+               may = smk_access_entry(smk_of_current(), dsp);
+
+               /*
+                * If the access rule allows transmutation and
+                * the directory requests transmutation then
+                * by all means transmute.
+                */
+               if (((may & MAY_TRANSMUTE) != 0) && smk_inode_transmutable(dir))
+                       isp = dsp;
+
                *value = kstrdup(isp, GFP_KERNEL);
                if (*value == NULL)
                        return -ENOMEM;
@@ -664,7 +715,8 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
 
        if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
            strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
-           strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
+           strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
+           strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
                if (!capable(CAP_MAC_ADMIN))
                        rc = -EPERM;
                /*
@@ -674,6 +726,12 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
                if (size == 0 || size >= SMK_LABELLEN ||
                    smk_import(value, size) == NULL)
                        rc = -EINVAL;
+       } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
+               if (!capable(CAP_MAC_ADMIN))
+                       rc = -EPERM;
+               if (size != TRANS_TRUE_SIZE ||
+                   strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
+                       rc = -EINVAL;
        } else
                rc = cap_inode_setxattr(dentry, name, value, size, flags);
 
@@ -700,26 +758,23 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
 static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
                                      const void *value, size_t size, int flags)
 {
-       struct inode_smack *isp;
        char *nsp;
+       struct inode_smack *isp = dentry->d_inode->i_security;
 
-       /*
-        * Not SMACK
-        */
-       if (strcmp(name, XATTR_NAME_SMACK))
-               return;
-
-       isp = dentry->d_inode->i_security;
-
-       /*
-        * No locking is done here. This is a pointer
-        * assignment.
-        */
-       nsp = smk_import(value, size);
-       if (nsp != NULL)
-               isp->smk_inode = nsp;
-       else
-               isp->smk_inode = smack_known_invalid.smk_known;
+       if (strcmp(name, XATTR_NAME_SMACK) == 0) {
+               nsp = smk_import(value, size);
+               if (nsp != NULL)
+                       isp->smk_inode = nsp;
+               else
+                       isp->smk_inode = smack_known_invalid.smk_known;
+       } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
+               nsp = smk_import(value, size);
+               if (nsp != NULL)
+                       isp->smk_task = nsp;
+               else
+                       isp->smk_task = smack_known_invalid.smk_known;
+       } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0)
+               isp->smk_flags |= SMK_INODE_TRANSMUTE;
 
        return;
 }
@@ -752,12 +807,15 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
  */
 static int smack_inode_removexattr(struct dentry *dentry, const char *name)
 {
+       struct inode_smack *isp;
        struct smk_audit_info ad;
        int rc = 0;
 
        if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
            strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
-           strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
+           strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
+           strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
+           strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
                if (!capable(CAP_MAC_ADMIN))
                        rc = -EPERM;
        } else
@@ -768,6 +826,11 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
        if (rc == 0)
                rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
 
+       if (rc == 0) {
+               isp = dentry->d_inode->i_security;
+               isp->smk_task = NULL;
+       }
+
        return rc;
 }
 
@@ -895,7 +958,7 @@ static int smack_file_permission(struct file *file, int mask)
  */
 static int smack_file_alloc_security(struct file *file)
 {
-       file->f_security = current_security();
+       file->f_security = smk_of_current();
        return 0;
 }
 
@@ -1005,7 +1068,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
  */
 static int smack_file_set_fowner(struct file *file)
 {
-       file->f_security = current_security();
+       file->f_security = smk_of_current();
        return 0;
 }
 
@@ -1025,7 +1088,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
 {
        struct file *file;
        int rc;
-       char *tsp = tsk->cred->security;
+       char *tsp = smk_of_task(tsk->cred->security);
        struct smk_audit_info ad;
 
        /*
@@ -1082,7 +1145,9 @@ static int smack_file_receive(struct file *file)
  */
 static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 {
-       cred->security = NULL;
+       cred->security = kzalloc(sizeof(struct task_smack), gfp);
+       if (cred->security == NULL)
+               return -ENOMEM;
        return 0;
 }
 
@@ -1097,7 +1162,7 @@ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
  */
 static void smack_cred_free(struct cred *cred)
 {
-       cred->security = NULL;
+       kfree(cred->security);
 }
 
 /**
@@ -1111,7 +1176,16 @@ static void smack_cred_free(struct cred *cred)
 static int smack_cred_prepare(struct cred *new, const struct cred *old,
                              gfp_t gfp)
 {
-       new->security = old->security;
+       struct task_smack *old_tsp = old->security;
+       struct task_smack *new_tsp;
+
+       new_tsp = kzalloc(sizeof(struct task_smack), gfp);
+       if (new_tsp == NULL)
+               return -ENOMEM;
+
+       new_tsp->smk_task = old_tsp->smk_task;
+       new_tsp->smk_forked = old_tsp->smk_task;
+       new->security = new_tsp;
        return 0;
 }
 
@@ -1124,7 +1198,11 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
  */
 static void smack_cred_transfer(struct cred *new, const struct cred *old)
 {
-       new->security = old->security;
+       struct task_smack *old_tsp = old->security;
+       struct task_smack *new_tsp = new->security;
+
+       new_tsp->smk_task = old_tsp->smk_task;
+       new_tsp->smk_forked = old_tsp->smk_task;
 }
 
 /**
@@ -1136,12 +1214,13 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
  */
 static int smack_kernel_act_as(struct cred *new, u32 secid)
 {
+       struct task_smack *new_tsp = new->security;
        char *smack = smack_from_secid(secid);
 
        if (smack == NULL)
                return -EINVAL;
 
-       new->security = smack;
+       new_tsp->smk_task = smack;
        return 0;
 }
 
@@ -1157,8 +1236,10 @@ static int smack_kernel_create_files_as(struct cred *new,
                                        struct inode *inode)
 {
        struct inode_smack *isp = inode->i_security;
+       struct task_smack *tsp = new->security;
 
-       new->security = isp->smk_inode;
+       tsp->smk_forked = isp->smk_inode;
+       tsp->smk_task = isp->smk_inode;
        return 0;
 }
 
@@ -1175,7 +1256,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access)
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, p);
-       return smk_curacc(task_security(p), access, &ad);
+       return smk_curacc(smk_of_task(task_security(p)), access, &ad);
 }
 
 /**
@@ -1221,7 +1302,7 @@ static int smack_task_getsid(struct task_struct *p)
  */
 static void smack_task_getsecid(struct task_struct *p, u32 *secid)
 {
-       *secid = smack_to_secid(task_security(p));
+       *secid = smack_to_secid(smk_of_task(task_security(p)));
 }
 
 /**
@@ -1333,14 +1414,15 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
         * can write the receiver.
         */
        if (secid == 0)
-               return smk_curacc(task_security(p), MAY_WRITE, &ad);
+               return smk_curacc(smk_of_task(task_security(p)), MAY_WRITE,
+                                 &ad);
        /*
         * If the secid isn't 0 we're dealing with some USB IO
         * specific behavior. This is not clean. For one thing
         * we can't take privilege into account.
         */
-       return smk_access(smack_from_secid(secid), task_security(p),
-                         MAY_WRITE, &ad);
+       return smk_access(smack_from_secid(secid),
+                         smk_of_task(task_security(p)), MAY_WRITE, &ad);
 }
 
 /**
@@ -1352,12 +1434,12 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
 static int smack_task_wait(struct task_struct *p)
 {
        struct smk_audit_info ad;
-       char *sp = current_security();
-       char *tsp = task_security(p);
+       char *sp = smk_of_current();
+       char *tsp = smk_of_forked(task_security(p));
        int rc;
 
        /* we don't log here, we can be overriden */
-       rc = smk_access(sp, tsp, MAY_WRITE, NULL);
+       rc = smk_access(tsp, sp, MAY_WRITE, NULL);
        if (rc == 0)
                goto out_log;
 
@@ -1378,7 +1460,7 @@ static int smack_task_wait(struct task_struct *p)
  out_log:
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, p);
-       smack_log(sp, tsp, MAY_WRITE, rc, &ad);
+       smack_log(tsp, sp, MAY_WRITE, rc, &ad);
        return rc;
 }
 
@@ -1392,7 +1474,7 @@ static int smack_task_wait(struct task_struct *p)
 static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
 {
        struct inode_smack *isp = inode->i_security;
-       isp->smk_inode = task_security(p);
+       isp->smk_inode = smk_of_task(task_security(p));
 }
 
 /*
@@ -1411,7 +1493,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
  */
 static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
 {
-       char *csp = current_security();
+       char *csp = smk_of_current();
        struct socket_smack *ssp;
 
        ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
@@ -1667,10 +1749,13 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
                ssp->smk_in = sp;
        else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
                ssp->smk_out = sp;
-               rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
-               if (rc != 0)
-                       printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
-                              __func__, -rc);
+               if (sock->sk->sk_family != PF_UNIX) {
+                       rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
+                       if (rc != 0)
+                               printk(KERN_WARNING
+                                       "Smack: \"%s\" netlbl error %d.\n",
+                                       __func__, -rc);
+               }
        } else
                return -EOPNOTSUPP;
 
@@ -1749,7 +1834,7 @@ static int smack_flags_to_may(int flags)
  */
 static int smack_msg_msg_alloc_security(struct msg_msg *msg)
 {
-       msg->security = current_security();
+       msg->security = smk_of_current();
        return 0;
 }
 
@@ -1785,7 +1870,7 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
 {
        struct kern_ipc_perm *isp = &shp->shm_perm;
 
-       isp->security = current_security();
+       isp->security = smk_of_current();
        return 0;
 }
 
@@ -1908,7 +1993,7 @@ static int smack_sem_alloc_security(struct sem_array *sma)
 {
        struct kern_ipc_perm *isp = &sma->sem_perm;
 
-       isp->security = current_security();
+       isp->security = smk_of_current();
        return 0;
 }
 
@@ -2026,7 +2111,7 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq)
 {
        struct kern_ipc_perm *kisp = &msq->q_perm;
 
-       kisp->security = current_security();
+       kisp->security = smk_of_current();
        return 0;
 }
 
@@ -2198,9 +2283,11 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
        struct super_block *sbp;
        struct superblock_smack *sbsp;
        struct inode_smack *isp;
-       char *csp = current_security();
+       char *csp = smk_of_current();
        char *fetched;
        char *final;
+       char trattr[TRANS_TRUE_SIZE];
+       int transflag = 0;
        struct dentry *dp;
 
        if (inode == NULL)
@@ -2267,9 +2354,10 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                break;
        case SOCKFS_MAGIC:
                /*
-                * Casey says sockets get the smack of the task.
+                * Socket access is controlled by the socket
+                * structures associated with the task involved.
                 */
-               final = csp;
+               final = smack_known_star.smk_known;
                break;
        case PROC_SUPER_MAGIC:
                /*
@@ -2296,7 +2384,16 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                /*
                 * This isn't an understood special case.
                 * Get the value from the xattr.
-                *
+                */
+
+               /*
+                * UNIX domain sockets use lower level socket data.
+                */
+               if (S_ISSOCK(inode->i_mode)) {
+                       final = smack_known_star.smk_known;
+                       break;
+               }
+               /*
                 * No xattr support means, alas, no SMACK label.
                 * Use the aforeapplied default.
                 * It would be curious if the label of the task
@@ -2308,9 +2405,21 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 * Get the dentry for xattr.
                 */
                dp = dget(opt_dentry);
-               fetched = smk_fetch(inode, dp);
-               if (fetched != NULL)
+               fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp);
+               if (fetched != NULL) {
                        final = fetched;
+                       if (S_ISDIR(inode->i_mode)) {
+                               trattr[0] = '\0';
+                               inode->i_op->getxattr(dp,
+                                       XATTR_NAME_SMACKTRANSMUTE,
+                                       trattr, TRANS_TRUE_SIZE);
+                               if (strncmp(trattr, TRANS_TRUE,
+                                           TRANS_TRUE_SIZE) == 0)
+                                       transflag = SMK_INODE_TRANSMUTE;
+                       }
+               }
+               isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);
+
                dput(dp);
                break;
        }
@@ -2320,7 +2429,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
        else
                isp->smk_inode = final;
 
-       isp->smk_flags |= SMK_INODE_INSTANT;
+       isp->smk_flags |= (SMK_INODE_INSTANT | transflag);
 
 unlockandout:
        mutex_unlock(&isp->smk_lock);
@@ -2345,7 +2454,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
        if (strcmp(name, "current") != 0)
                return -EINVAL;
 
-       cp = kstrdup(task_security(p), GFP_KERNEL);
+       cp = kstrdup(smk_of_task(task_security(p)), GFP_KERNEL);
        if (cp == NULL)
                return -ENOMEM;
 
@@ -2369,6 +2478,8 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
 static int smack_setprocattr(struct task_struct *p, char *name,
                             void *value, size_t size)
 {
+       struct task_smack *tsp;
+       struct task_smack *oldtsp;
        struct cred *new;
        char *newsmack;
 
@@ -2398,10 +2509,18 @@ static int smack_setprocattr(struct task_struct *p, char *name,
        if (newsmack == smack_known_web.smk_known)
                return -EPERM;
 
+       oldtsp = p->cred->security;
        new = prepare_creds();
        if (new == NULL)
                return -ENOMEM;
-       new->security = newsmack;
+       tsp = kzalloc(sizeof(struct task_smack), GFP_KERNEL);
+       if (tsp == NULL) {
+               kfree(new);
+               return -ENOMEM;
+       }
+       tsp->smk_task = newsmack;
+       tsp->smk_forked = oldtsp->smk_forked;
+       new->security = tsp;
        commit_creds(new);
        return size;
 }
@@ -2418,14 +2537,18 @@ static int smack_setprocattr(struct task_struct *p, char *name,
 static int smack_unix_stream_connect(struct sock *sock,
                                     struct sock *other, struct sock *newsk)
 {
-       struct inode *sp = SOCK_INODE(sock->sk_socket);
-       struct inode *op = SOCK_INODE(other->sk_socket);
+       struct socket_smack *ssp = sock->sk_security;
+       struct socket_smack *osp = other->sk_security;
        struct smk_audit_info ad;
+       int rc = 0;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
        smk_ad_setfield_u_net_sk(&ad, other);
-       return smk_access(smk_of_inode(sp), smk_of_inode(op),
-                                MAY_READWRITE, &ad);
+
+       if (!capable(CAP_MAC_OVERRIDE))
+               rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
+
+       return rc;
 }
 
 /**
@@ -2438,13 +2561,18 @@ static int smack_unix_stream_connect(struct sock *sock,
  */
 static int smack_unix_may_send(struct socket *sock, struct socket *other)
 {
-       struct inode *sp = SOCK_INODE(sock);
-       struct inode *op = SOCK_INODE(other);
+       struct socket_smack *ssp = sock->sk->sk_security;
+       struct socket_smack *osp = other->sk->sk_security;
        struct smk_audit_info ad;
+       int rc = 0;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
        smk_ad_setfield_u_net_sk(&ad, other->sk);
-       return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE, &ad);
+
+       if (!capable(CAP_MAC_OVERRIDE))
+               rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
+
+       return rc;
 }
 
 /**
@@ -2629,7 +2757,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
 
 /**
  * smack_socket_getpeersec_dgram - pull in packet label
- * @sock: the socket
+ * @sock: the peer socket
  * @skb: packet data
  * @secid: pointer to where to put the secid of the packet
  *
@@ -2640,41 +2768,39 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
 
 {
        struct netlbl_lsm_secattr secattr;
-       struct sock *sk;
+       struct socket_smack *sp;
        char smack[SMK_LABELLEN];
-       int family = PF_INET;
-       u32 s;
+       int family = PF_UNSPEC;
+       u32 s = 0;      /* 0 is the invalid secid */
        int rc;
 
-       /*
-        * Only works for families with packets.
-        */
-       if (sock != NULL) {
-               sk = sock->sk;
-               if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
-                       return 0;
-               family = sk->sk_family;
+       if (skb != NULL) {
+               if (skb->protocol == htons(ETH_P_IP))
+                       family = PF_INET;
+               else if (skb->protocol == htons(ETH_P_IPV6))
+                       family = PF_INET6;
        }
-       /*
-        * Translate what netlabel gave us.
-        */
-       netlbl_secattr_init(&secattr);
-       rc = netlbl_skbuff_getattr(skb, family, &secattr);
-       if (rc == 0)
-               smack_from_secattr(&secattr, smack);
-       netlbl_secattr_destroy(&secattr);
+       if (family == PF_UNSPEC && sock != NULL)
+               family = sock->sk->sk_family;
 
-       /*
-        * Give up if we couldn't get anything
-        */
-       if (rc != 0)
-               return rc;
-
-       s = smack_to_secid(smack);
+       if (family == PF_UNIX) {
+               sp = sock->sk->sk_security;
+               s = smack_to_secid(sp->smk_out);
+       } else if (family == PF_INET || family == PF_INET6) {
+               /*
+                * Translate what netlabel gave us.
+                */
+               netlbl_secattr_init(&secattr);
+               rc = netlbl_skbuff_getattr(skb, family, &secattr);
+               if (rc == 0) {
+                       smack_from_secattr(&secattr, smack);
+                       s = smack_to_secid(smack);
+               }
+               netlbl_secattr_destroy(&secattr);
+       }
+       *secid = s;
        if (s == 0)
                return -EINVAL;
-
-       *secid = s;
        return 0;
 }
 
@@ -2695,7 +2821,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
                return;
 
        ssp = sk->sk_security;
-       ssp->smk_in = ssp->smk_out = current_security();
+       ssp->smk_in = ssp->smk_out = smk_of_current();
        /* cssp->smk_packet is already set in smack_inet_csk_clone() */
 }
 
@@ -2816,7 +2942,7 @@ static void smack_inet_csk_clone(struct sock *sk,
 static int smack_key_alloc(struct key *key, const struct cred *cred,
                           unsigned long flags)
 {
-       key->security = cred->security;
+       key->security = smk_of_task(cred->security);
        return 0;
 }
 
@@ -2845,6 +2971,7 @@ static int smack_key_permission(key_ref_t key_ref,
 {
        struct key *keyp;
        struct smk_audit_info ad;
+       char *tsp = smk_of_task(cred->security);
 
        keyp = key_ref_to_ptr(key_ref);
        if (keyp == NULL)
@@ -2858,14 +2985,14 @@ static int smack_key_permission(key_ref_t key_ref,
        /*
         * This should not occur
         */
-       if (cred->security == NULL)
+       if (tsp == NULL)
                return -EACCES;
 #ifdef CONFIG_AUDIT
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY);
        ad.a.u.key_struct.key = keyp->serial;
        ad.a.u.key_struct.key_desc = keyp->description;
 #endif
-       return smk_access(cred->security, keyp->security,
+       return smk_access(tsp, keyp->security,
                                 MAY_READWRITE, &ad);
 }
 #endif /* CONFIG_KEYS */
@@ -3067,6 +3194,8 @@ struct security_operations smack_ops = {
        .sb_mount =                     smack_sb_mount,
        .sb_umount =                    smack_sb_umount,
 
+       .bprm_set_creds =               smack_bprm_set_creds,
+
        .inode_alloc_security =         smack_inode_alloc_security,
        .inode_free_security =          smack_inode_free_security,
        .inode_init_security =          smack_inode_init_security,
@@ -3203,9 +3332,16 @@ static __init void init_smack_know_list(void)
 static __init int smack_init(void)
 {
        struct cred *cred;
+       struct task_smack *tsp;
 
-       if (!security_module_enable(&smack_ops))
+       tsp = kzalloc(sizeof(struct task_smack), GFP_KERNEL);
+       if (tsp == NULL)
+               return -ENOMEM;
+
+       if (!security_module_enable(&smack_ops)) {
+               kfree(tsp);
                return 0;
+       }
 
        printk(KERN_INFO "Smack:  Initializing.\n");
 
@@ -3213,7 +3349,9 @@ static __init int smack_init(void)
         * Set the security state for the initial task.
         */
        cred = (struct cred *) current->cred;
-       cred->security = &smack_known_floor.smk_known;
+       tsp->smk_forked = smack_known_floor.smk_known;
+       tsp->smk_task = smack_known_floor.smk_known;
+       cred->security = tsp;
 
        /* initialize the smack_know_list */
        init_smack_know_list();
index dc1fd6239f243ad1f4e254db0ead6707a1d7c077..362d5eda948be93a0671127b85dc55f8e2a04c95 100644 (file)
@@ -109,9 +109,12 @@ const char *smack_cipso_option = SMACK_CIPSO_OPTION;
  * SMK_ACCESSLEN: Maximum length for a rule access field
  * SMK_LOADLEN: Smack rule length
  */
-#define SMK_ACCESS    "rwxa"
-#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1)
-#define SMK_LOADLEN   (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
+#define SMK_OACCESS    "rwxa"
+#define SMK_ACCESS     "rwxat"
+#define SMK_OACCESSLEN (sizeof(SMK_OACCESS) - 1)
+#define SMK_ACCESSLEN  (sizeof(SMK_ACCESS) - 1)
+#define SMK_OLOADLEN   (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN)
+#define SMK_LOADLEN    (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
 
 /**
  * smk_netlabel_audit_set - fill a netlbl_audit struct
@@ -121,7 +124,7 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
 {
        nap->loginuid = audit_get_loginuid(current);
        nap->sessionid = audit_get_sessionid(current);
-       nap->secid = smack_to_secid(current_security());
+       nap->secid = smack_to_secid(smk_of_current());
 }
 
 /*
@@ -175,6 +178,8 @@ static int load_seq_show(struct seq_file *s, void *v)
                seq_putc(s, 'x');
        if (srp->smk_access & MAY_APPEND)
                seq_putc(s, 'a');
+       if (srp->smk_access & MAY_TRANSMUTE)
+               seq_putc(s, 't');
        if (srp->smk_access == 0)
                seq_putc(s, '-');
 
@@ -273,10 +278,15 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
        if (!capable(CAP_MAC_ADMIN))
                return -EPERM;
 
-       if (*ppos != 0 || count != SMK_LOADLEN)
+       if (*ppos != 0)
+               return -EINVAL;
+       /*
+        * Minor hack for backward compatability
+        */
+       if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN)
                return -EINVAL;
 
-       data = kzalloc(count, GFP_KERNEL);
+       data = kzalloc(SMK_LOADLEN, GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
 
@@ -285,6 +295,12 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
                goto out;
        }
 
+       /*
+        * More on the minor hack for backward compatability
+        */
+       if (count == (SMK_OLOADLEN))
+               data[SMK_OLOADLEN] = '-';
+
        rule = kzalloc(sizeof(*rule), GFP_KERNEL);
        if (rule == NULL) {
                rc = -ENOMEM;
@@ -345,6 +361,17 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
                goto out_free_rule;
        }
 
+       switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) {
+       case '-':
+               break;
+       case 't':
+       case 'T':
+               rule->smk_access |= MAY_TRANSMUTE;
+               break;
+       default:
+               goto out_free_rule;
+       }
+
        rc = smk_set_access(rule);
 
        if (!rc)
@@ -1160,7 +1187,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 {
        char in[SMK_LABELLEN];
-       char *sp = current->cred->security;
+       char *sp = smk_of_task(current->cred->security);
 
        if (!capable(CAP_MAC_ADMIN))
                return -EPERM;
index b439eee462cb720ec622628fa78b955e846980ae..8ad93ee2e92bfe312157b46eabbe251b9db35f9d 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/pxa2xx_ssp.h>
 
 #include <asm/irq.h>
 
@@ -33,7 +34,6 @@
 #include <mach/hardware.h>
 #include <mach/dma.h>
 #include <mach/audio.h>
-#include <plat/ssp.h>
 
 #include "../../arm/pxa2xx-pcm.h"
 #include "pxa-ssp.h"
similarity index 99%
rename from Documentation/vm/slabinfo.c
rename to tools/slub/slabinfo.c
index 92e729f4b676e39851a06760626915950a561035..516551c9f1722f76eeaab3be04164e8ed62ee75e 100644 (file)
@@ -607,7 +607,7 @@ static int debug_opt_scan(char *opt)
        }
 
        for ( ; *opt; opt++)
-               switch (*opt) {
+               switch (*opt) {
                case 'F' : case 'f':
                        if (sanity)
                                return 0;
@@ -1127,7 +1127,7 @@ static void read_slab_dir(void)
                                continue;
                switch (de->d_type) {
                   case DT_LNK:
-                       alias->name = strdup(de->d_name);
+                       alias->name = strdup(de->d_name);
                        count = readlink(de->d_name, buffer, sizeof(buffer));
 
                        if (count < 0)
@@ -1143,7 +1143,7 @@ static void read_slab_dir(void)
                   case DT_DIR:
                        if (chdir(de->d_name))
                                fatal("Unable to access slab %s\n", slab->name);
-                       slab->name = strdup(de->d_name);
+                       slab->name = strdup(de->d_name);
                        slab->alias = 0;
                        slab->refs = 0;
                        slab->aliases = get_obj("aliases");
index b2b3c2d1cf8bd37849d92b9a1d06131f1cf14f96..7f06884ecd41b588d829064a53ac964395b0ae1e 100644 (file)
@@ -104,6 +104,8 @@ static int cpio_mkslink(const char *name, const char *target,
        char s[256];
        time_t mtime = time(NULL);
 
+       if (name[0] == '/')
+               name++;
        sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
               "%08X%08X%08X%08X%08X%08X%08X",
                "070701",               /* magic */
@@ -152,6 +154,8 @@ static int cpio_mkgeneric(const char *name, unsigned int mode,
        char s[256];
        time_t mtime = time(NULL);
 
+       if (name[0] == '/')
+               name++;
        sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
               "%08X%08X%08X%08X%08X%08X%08X",
                "070701",               /* magic */
@@ -245,6 +249,8 @@ static int cpio_mknod(const char *name, unsigned int mode,
        else
                mode |= S_IFCHR;
 
+       if (name[0] == '/')
+               name++;
        sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
               "%08X%08X%08X%08X%08X%08X%08X",
                "070701",               /* magic */
@@ -303,18 +309,18 @@ static int cpio_mkfile(const char *name, const char *location,
 
        mode |= S_IFREG;
 
-       retval = stat (location, &buf);
-       if (retval) {
-               fprintf (stderr, "File %s could not be located\n", location);
-               goto error;
-       }
-
        file = open (location, O_RDONLY);
        if (file < 0) {
                fprintf (stderr, "File %s could not be opened for reading\n", location);
                goto error;
        }
 
+       retval = fstat(file, &buf);
+       if (retval) {
+               fprintf(stderr, "File %s could not be stat()'ed\n", location);
+               goto error;
+       }
+
        filebuf = malloc(buf.st_size);
        if (!filebuf) {
                fprintf (stderr, "out of memory\n");
@@ -332,6 +338,8 @@ static int cpio_mkfile(const char *name, const char *location,
                /* data goes on last link */
                if (i == nlinks) size = buf.st_size;
 
+               if (name[0] == '/')
+                       name++;
                namesize = strlen(name) + 1;
                sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
                       "%08lX%08X%08X%08X%08X%08X%08X",