Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Jan 2011 19:18:59 +0000 (11:18 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Jan 2011 19:18:59 +0000 (11:18 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (30 commits)
  MAINTAINERS: Add tomoyo-dev-en ML.
  SELinux: define permissions for DCB netlink messages
  encrypted-keys: style and other cleanup
  encrypted-keys: verify datablob size before converting to binary
  trusted-keys: kzalloc and other cleanup
  trusted-keys: additional TSS return code and other error handling
  syslog: check cap_syslog when dmesg_restrict
  Smack: Transmute labels on specified directories
  selinux: cache sidtab_context_to_sid results
  SELinux: do not compute transition labels on mountpoint labeled filesystems
  This patch adds a new security attribute to Smack called SMACK64EXEC. It defines label that is used while task is running.
  SELinux: merge policydb_index_classes and policydb_index_others
  selinux: convert part of the sym_val_to_name array to use flex_array
  selinux: convert type_val_to_struct to flex_array
  flex_array: fix flex_array_put_ptr macro to be valid C
  SELinux: do not set automatic i_ino in selinuxfs
  selinux: rework security_netlbl_secattr_to_sid
  SELinux: standardize return code handling in selinuxfs.c
  SELinux: standardize return code handling in selinuxfs.c
  SELinux: standardize return code handling in policydb.c
  ...

333 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/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/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/vm/Makefile
Documentation/vm/slabinfo.c [deleted file]
MAINTAINERS
Makefile
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/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/include/asm/hypervisor.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/kernel/apic/apic.c
arch/x86/xen/enlighten.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-scsi.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/char/ipmi/ipmi_si_intf.c
drivers/char/snsc.h
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/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/mouse/bcm5974.c
drivers/misc/eeprom/at24.c
drivers/mmc/host/Kconfig
drivers/mmc/host/sdhci-of-core.c
drivers/mtd/Kconfig
drivers/mtd/maps/Kconfig
drivers/net/bonding/bonding.h
drivers/net/fs_enet/fs_enet-main.c
drivers/net/gianfar.c
drivers/net/ucc_geth.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/s390/char/tape_class.h
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/spi.c
drivers/usb/core/driver.c
drivers/usb/musb/musb_debugfs.c
drivers/video/xen-fbfront.c
drivers/xen/events.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/namei.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/sysfs/inode.c
fs/sysfs/sysfs.h
include/asm-generic/vmlinux.lds.h
include/linux/Kbuild
include/linux/audit.h
include/linux/dcache.h
include/linux/dcookies.h
include/linux/device.h
include/linux/firewire.h
include/linux/firmware-map.h
include/linux/fs.h
include/linux/fuse.h
include/linux/hid.h
include/linux/hrtimer.h
include/linux/i2c/ds620.h [new file with mode: 0644]
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/pipe_fs_i.h
include/linux/pm.h
include/linux/pm_runtime.h
include/linux/sched.h
include/linux/slab_def.h
include/linux/slub_def.h
include/linux/sunrpc/cache.h
include/linux/suspend.h
kernel/Makefile
kernel/freezer.c
kernel/power/Makefile
kernel/power/hibernate.c
kernel/power/process.c
kernel/power/suspend.c
mm/slab.c
mm/slub.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/apparmor/include/file.h
security/apparmor/include/match.h
security/selinux/include/avc.h
tools/slub/slabinfo.c [new file with mode: 0644]
usr/gen_init_cpio.c

index 063bda7..698b808 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 ad1125b..1c37b82 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 4a276ea..96b6903 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
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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 6456990..c6559f1 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 1e5165a..4a99031 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 2fe93ca..b507d61 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 0ef00bd..86e3cd0 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
 
index f2481ca..951eb9f 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 7f7a737..638afdf 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 41cc7b3..ffe55ff 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 9dcff32..3fa4d06 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)
diff --git a/Documentation/vm/slabinfo.c b/Documentation/vm/slabinfo.c
deleted file mode 100644 (file)
index 92e729f..0000000
+++ /dev/null
@@ -1,1364 +0,0 @@
-/*
- * Slabinfo: Tool to get reports about slabs
- *
- * (C) 2007 sgi, Christoph Lameter
- *
- * Compile by:
- *
- * gcc -o slabinfo slabinfo.c
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <strings.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <getopt.h>
-#include <regex.h>
-#include <errno.h>
-
-#define MAX_SLABS 500
-#define MAX_ALIASES 500
-#define MAX_NODES 1024
-
-struct slabinfo {
-       char *name;
-       int alias;
-       int refs;
-       int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
-       int hwcache_align, object_size, objs_per_slab;
-       int sanity_checks, slab_size, store_user, trace;
-       int order, poison, reclaim_account, red_zone;
-       unsigned long partial, objects, slabs, objects_partial, objects_total;
-       unsigned long alloc_fastpath, alloc_slowpath;
-       unsigned long free_fastpath, free_slowpath;
-       unsigned long free_frozen, free_add_partial, free_remove_partial;
-       unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
-       unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
-       unsigned long deactivate_to_head, deactivate_to_tail;
-       unsigned long deactivate_remote_frees, order_fallback;
-       int numa[MAX_NODES];
-       int numa_partial[MAX_NODES];
-} slabinfo[MAX_SLABS];
-
-struct aliasinfo {
-       char *name;
-       char *ref;
-       struct slabinfo *slab;
-} aliasinfo[MAX_ALIASES];
-
-int slabs = 0;
-int actual_slabs = 0;
-int aliases = 0;
-int alias_targets = 0;
-int highest_node = 0;
-
-char buffer[4096];
-
-int show_empty = 0;
-int show_report = 0;
-int show_alias = 0;
-int show_slab = 0;
-int skip_zero = 1;
-int show_numa = 0;
-int show_track = 0;
-int show_first_alias = 0;
-int validate = 0;
-int shrink = 0;
-int show_inverted = 0;
-int show_single_ref = 0;
-int show_totals = 0;
-int sort_size = 0;
-int sort_active = 0;
-int set_debug = 0;
-int show_ops = 0;
-int show_activity = 0;
-
-/* Debug options */
-int sanity = 0;
-int redzone = 0;
-int poison = 0;
-int tracking = 0;
-int tracing = 0;
-
-int page_size;
-
-regex_t pattern;
-
-static void fatal(const char *x, ...)
-{
-       va_list ap;
-
-       va_start(ap, x);
-       vfprintf(stderr, x, ap);
-       va_end(ap);
-       exit(EXIT_FAILURE);
-}
-
-static void usage(void)
-{
-       printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n"
-               "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
-               "-a|--aliases           Show aliases\n"
-               "-A|--activity          Most active slabs first\n"
-               "-d<options>|--debug=<options> Set/Clear Debug options\n"
-               "-D|--display-active    Switch line format to activity\n"
-               "-e|--empty             Show empty slabs\n"
-               "-f|--first-alias       Show first alias\n"
-               "-h|--help              Show usage information\n"
-               "-i|--inverted          Inverted list\n"
-               "-l|--slabs             Show slabs\n"
-               "-n|--numa              Show NUMA information\n"
-               "-o|--ops               Show kmem_cache_ops\n"
-               "-s|--shrink            Shrink slabs\n"
-               "-r|--report            Detailed report on single slabs\n"
-               "-S|--Size              Sort by size\n"
-               "-t|--tracking          Show alloc/free information\n"
-               "-T|--Totals            Show summary information\n"
-               "-v|--validate          Validate slabs\n"
-               "-z|--zero              Include empty slabs\n"
-               "-1|--1ref              Single reference\n"
-               "\nValid debug options (FZPUT may be combined)\n"
-               "a / A          Switch on all debug options (=FZUP)\n"
-               "-              Switch off all debug options\n"
-               "f / F          Sanity Checks (SLAB_DEBUG_FREE)\n"
-               "z / Z          Redzoning\n"
-               "p / P          Poisoning\n"
-               "u / U          Tracking\n"
-               "t / T          Tracing\n"
-       );
-}
-
-static unsigned long read_obj(const char *name)
-{
-       FILE *f = fopen(name, "r");
-
-       if (!f)
-               buffer[0] = 0;
-       else {
-               if (!fgets(buffer, sizeof(buffer), f))
-                       buffer[0] = 0;
-               fclose(f);
-               if (buffer[strlen(buffer)] == '\n')
-                       buffer[strlen(buffer)] = 0;
-       }
-       return strlen(buffer);
-}
-
-
-/*
- * Get the contents of an attribute
- */
-static unsigned long get_obj(const char *name)
-{
-       if (!read_obj(name))
-               return 0;
-
-       return atol(buffer);
-}
-
-static unsigned long get_obj_and_str(const char *name, char **x)
-{
-       unsigned long result = 0;
-       char *p;
-
-       *x = NULL;
-
-       if (!read_obj(name)) {
-               x = NULL;
-               return 0;
-       }
-       result = strtoul(buffer, &p, 10);
-       while (*p == ' ')
-               p++;
-       if (*p)
-               *x = strdup(p);
-       return result;
-}
-
-static void set_obj(struct slabinfo *s, const char *name, int n)
-{
-       char x[100];
-       FILE *f;
-
-       snprintf(x, 100, "%s/%s", s->name, name);
-       f = fopen(x, "w");
-       if (!f)
-               fatal("Cannot write to %s\n", x);
-
-       fprintf(f, "%d\n", n);
-       fclose(f);
-}
-
-static unsigned long read_slab_obj(struct slabinfo *s, const char *name)
-{
-       char x[100];
-       FILE *f;
-       size_t l;
-
-       snprintf(x, 100, "%s/%s", s->name, name);
-       f = fopen(x, "r");
-       if (!f) {
-               buffer[0] = 0;
-               l = 0;
-       } else {
-               l = fread(buffer, 1, sizeof(buffer), f);
-               buffer[l] = 0;
-               fclose(f);
-       }
-       return l;
-}
-
-
-/*
- * Put a size string together
- */
-static int store_size(char *buffer, unsigned long value)
-{
-       unsigned long divisor = 1;
-       char trailer = 0;
-       int n;
-
-       if (value > 1000000000UL) {
-               divisor = 100000000UL;
-               trailer = 'G';
-       } else if (value > 1000000UL) {
-               divisor = 100000UL;
-               trailer = 'M';
-       } else if (value > 1000UL) {
-               divisor = 100;
-               trailer = 'K';
-       }
-
-       value /= divisor;
-       n = sprintf(buffer, "%ld",value);
-       if (trailer) {
-               buffer[n] = trailer;
-               n++;
-               buffer[n] = 0;
-       }
-       if (divisor != 1) {
-               memmove(buffer + n - 2, buffer + n - 3, 4);
-               buffer[n-2] = '.';
-               n++;
-       }
-       return n;
-}
-
-static void decode_numa_list(int *numa, char *t)
-{
-       int node;
-       int nr;
-
-       memset(numa, 0, MAX_NODES * sizeof(int));
-
-       if (!t)
-               return;
-
-       while (*t == 'N') {
-               t++;
-               node = strtoul(t, &t, 10);
-               if (*t == '=') {
-                       t++;
-                       nr = strtoul(t, &t, 10);
-                       numa[node] = nr;
-                       if (node > highest_node)
-                               highest_node = node;
-               }
-               while (*t == ' ')
-                       t++;
-       }
-}
-
-static void slab_validate(struct slabinfo *s)
-{
-       if (strcmp(s->name, "*") == 0)
-               return;
-
-       set_obj(s, "validate", 1);
-}
-
-static void slab_shrink(struct slabinfo *s)
-{
-       if (strcmp(s->name, "*") == 0)
-               return;
-
-       set_obj(s, "shrink", 1);
-}
-
-int line = 0;
-
-static void first_line(void)
-{
-       if (show_activity)
-               printf("Name                   Objects      Alloc       Free   %%Fast Fallb O\n");
-       else
-               printf("Name                   Objects Objsize    Space "
-                       "Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
-}
-
-/*
- * Find the shortest alias of a slab
- */
-static struct aliasinfo *find_one_alias(struct slabinfo *find)
-{
-       struct aliasinfo *a;
-       struct aliasinfo *best = NULL;
-
-       for(a = aliasinfo;a < aliasinfo + aliases; a++) {
-               if (a->slab == find &&
-                       (!best || strlen(best->name) < strlen(a->name))) {
-                               best = a;
-                               if (strncmp(a->name,"kmall", 5) == 0)
-                                       return best;
-                       }
-       }
-       return best;
-}
-
-static unsigned long slab_size(struct slabinfo *s)
-{
-       return  s->slabs * (page_size << s->order);
-}
-
-static unsigned long slab_activity(struct slabinfo *s)
-{
-       return  s->alloc_fastpath + s->free_fastpath +
-               s->alloc_slowpath + s->free_slowpath;
-}
-
-static void slab_numa(struct slabinfo *s, int mode)
-{
-       int node;
-
-       if (strcmp(s->name, "*") == 0)
-               return;
-
-       if (!highest_node) {
-               printf("\n%s: No NUMA information available.\n", s->name);
-               return;
-       }
-
-       if (skip_zero && !s->slabs)
-               return;
-
-       if (!line) {
-               printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
-               for(node = 0; node <= highest_node; node++)
-                       printf(" %4d", node);
-               printf("\n----------------------");
-               for(node = 0; node <= highest_node; node++)
-                       printf("-----");
-               printf("\n");
-       }
-       printf("%-21s ", mode ? "All slabs" : s->name);
-       for(node = 0; node <= highest_node; node++) {
-               char b[20];
-
-               store_size(b, s->numa[node]);
-               printf(" %4s", b);
-       }
-       printf("\n");
-       if (mode) {
-               printf("%-21s ", "Partial slabs");
-               for(node = 0; node <= highest_node; node++) {
-                       char b[20];
-
-                       store_size(b, s->numa_partial[node]);
-                       printf(" %4s", b);
-               }
-               printf("\n");
-       }
-       line++;
-}
-
-static void show_tracking(struct slabinfo *s)
-{
-       printf("\n%s: Kernel object allocation\n", s->name);
-       printf("-----------------------------------------------------------------------\n");
-       if (read_slab_obj(s, "alloc_calls"))
-               printf(buffer);
-       else
-               printf("No Data\n");
-
-       printf("\n%s: Kernel object freeing\n", s->name);
-       printf("------------------------------------------------------------------------\n");
-       if (read_slab_obj(s, "free_calls"))
-               printf(buffer);
-       else
-               printf("No Data\n");
-
-}
-
-static void ops(struct slabinfo *s)
-{
-       if (strcmp(s->name, "*") == 0)
-               return;
-
-       if (read_slab_obj(s, "ops")) {
-               printf("\n%s: kmem_cache operations\n", s->name);
-               printf("--------------------------------------------\n");
-               printf(buffer);
-       } else
-               printf("\n%s has no kmem_cache operations\n", s->name);
-}
-
-static const char *onoff(int x)
-{
-       if (x)
-               return "On ";
-       return "Off";
-}
-
-static void slab_stats(struct slabinfo *s)
-{
-       unsigned long total_alloc;
-       unsigned long total_free;
-       unsigned long total;
-
-       if (!s->alloc_slab)
-               return;
-
-       total_alloc = s->alloc_fastpath + s->alloc_slowpath;
-       total_free = s->free_fastpath + s->free_slowpath;
-
-       if (!total_alloc)
-               return;
-
-       printf("\n");
-       printf("Slab Perf Counter       Alloc     Free %%Al %%Fr\n");
-       printf("--------------------------------------------------\n");
-       printf("Fastpath             %8lu %8lu %3lu %3lu\n",
-               s->alloc_fastpath, s->free_fastpath,
-               s->alloc_fastpath * 100 / total_alloc,
-               s->free_fastpath * 100 / total_free);
-       printf("Slowpath             %8lu %8lu %3lu %3lu\n",
-               total_alloc - s->alloc_fastpath, s->free_slowpath,
-               (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
-               s->free_slowpath * 100 / total_free);
-       printf("Page Alloc           %8lu %8lu %3lu %3lu\n",
-               s->alloc_slab, s->free_slab,
-               s->alloc_slab * 100 / total_alloc,
-               s->free_slab * 100 / total_free);
-       printf("Add partial          %8lu %8lu %3lu %3lu\n",
-               s->deactivate_to_head + s->deactivate_to_tail,
-               s->free_add_partial,
-               (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
-               s->free_add_partial * 100 / total_free);
-       printf("Remove partial       %8lu %8lu %3lu %3lu\n",
-               s->alloc_from_partial, s->free_remove_partial,
-               s->alloc_from_partial * 100 / total_alloc,
-               s->free_remove_partial * 100 / total_free);
-
-       printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
-               s->deactivate_remote_frees, s->free_frozen,
-               s->deactivate_remote_frees * 100 / total_alloc,
-               s->free_frozen * 100 / total_free);
-
-       printf("Total                %8lu %8lu\n\n", total_alloc, total_free);
-
-       if (s->cpuslab_flush)
-               printf("Flushes %8lu\n", s->cpuslab_flush);
-
-       if (s->alloc_refill)
-               printf("Refill %8lu\n", s->alloc_refill);
-
-       total = s->deactivate_full + s->deactivate_empty +
-                       s->deactivate_to_head + s->deactivate_to_tail;
-
-       if (total)
-               printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) "
-                       "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n",
-                       s->deactivate_full, (s->deactivate_full * 100) / total,
-                       s->deactivate_empty, (s->deactivate_empty * 100) / total,
-                       s->deactivate_to_head, (s->deactivate_to_head * 100) / total,
-                       s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
-}
-
-static void report(struct slabinfo *s)
-{
-       if (strcmp(s->name, "*") == 0)
-               return;
-
-       printf("\nSlabcache: %-20s  Aliases: %2d Order : %2d Objects: %lu\n",
-               s->name, s->aliases, s->order, s->objects);
-       if (s->hwcache_align)
-               printf("** Hardware cacheline aligned\n");
-       if (s->cache_dma)
-               printf("** Memory is allocated in a special DMA zone\n");
-       if (s->destroy_by_rcu)
-               printf("** Slabs are destroyed via RCU\n");
-       if (s->reclaim_account)
-               printf("** Reclaim accounting active\n");
-
-       printf("\nSizes (bytes)     Slabs              Debug                Memory\n");
-       printf("------------------------------------------------------------------------\n");
-       printf("Object : %7d  Total  : %7ld   Sanity Checks : %s  Total: %7ld\n",
-                       s->object_size, s->slabs, onoff(s->sanity_checks),
-                       s->slabs * (page_size << s->order));
-       printf("SlabObj: %7d  Full   : %7ld   Redzoning     : %s  Used : %7ld\n",
-                       s->slab_size, s->slabs - s->partial - s->cpu_slabs,
-                       onoff(s->red_zone), s->objects * s->object_size);
-       printf("SlabSiz: %7d  Partial: %7ld   Poisoning     : %s  Loss : %7ld\n",
-                       page_size << s->order, s->partial, onoff(s->poison),
-                       s->slabs * (page_size << s->order) - s->objects * s->object_size);
-       printf("Loss   : %7d  CpuSlab: %7d   Tracking      : %s  Lalig: %7ld\n",
-                       s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
-                       (s->slab_size - s->object_size) * s->objects);
-       printf("Align  : %7d  Objects: %7d   Tracing       : %s  Lpadd: %7ld\n",
-                       s->align, s->objs_per_slab, onoff(s->trace),
-                       ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
-                       s->slabs);
-
-       ops(s);
-       show_tracking(s);
-       slab_numa(s, 1);
-       slab_stats(s);
-}
-
-static void slabcache(struct slabinfo *s)
-{
-       char size_str[20];
-       char dist_str[40];
-       char flags[20];
-       char *p = flags;
-
-       if (strcmp(s->name, "*") == 0)
-               return;
-
-       if (actual_slabs == 1) {
-               report(s);
-               return;
-       }
-
-       if (skip_zero && !show_empty && !s->slabs)
-               return;
-
-       if (show_empty && s->slabs)
-               return;
-
-       store_size(size_str, slab_size(s));
-       snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs,
-                                               s->partial, s->cpu_slabs);
-
-       if (!line++)
-               first_line();
-
-       if (s->aliases)
-               *p++ = '*';
-       if (s->cache_dma)
-               *p++ = 'd';
-       if (s->hwcache_align)
-               *p++ = 'A';
-       if (s->poison)
-               *p++ = 'P';
-       if (s->reclaim_account)
-               *p++ = 'a';
-       if (s->red_zone)
-               *p++ = 'Z';
-       if (s->sanity_checks)
-               *p++ = 'F';
-       if (s->store_user)
-               *p++ = 'U';
-       if (s->trace)
-               *p++ = 'T';
-
-       *p = 0;
-       if (show_activity) {
-               unsigned long total_alloc;
-               unsigned long total_free;
-
-               total_alloc = s->alloc_fastpath + s->alloc_slowpath;
-               total_free = s->free_fastpath + s->free_slowpath;
-
-               printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d\n",
-                       s->name, s->objects,
-                       total_alloc, total_free,
-                       total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
-                       total_free ? (s->free_fastpath * 100 / total_free) : 0,
-                       s->order_fallback, s->order);
-       }
-       else
-               printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
-                       s->name, s->objects, s->object_size, size_str, dist_str,
-                       s->objs_per_slab, s->order,
-                       s->slabs ? (s->partial * 100) / s->slabs : 100,
-                       s->slabs ? (s->objects * s->object_size * 100) /
-                               (s->slabs * (page_size << s->order)) : 100,
-                       flags);
-}
-
-/*
- * Analyze debug options. Return false if something is amiss.
- */
-static int debug_opt_scan(char *opt)
-{
-       if (!opt || !opt[0] || strcmp(opt, "-") == 0)
-               return 1;
-
-       if (strcasecmp(opt, "a") == 0) {
-               sanity = 1;
-               poison = 1;
-               redzone = 1;
-               tracking = 1;
-               return 1;
-       }
-
-       for ( ; *opt; opt++)
-               switch (*opt) {
-               case 'F' : case 'f':
-                       if (sanity)
-                               return 0;
-                       sanity = 1;
-                       break;
-               case 'P' : case 'p':
-                       if (poison)
-                               return 0;
-                       poison = 1;
-                       break;
-
-               case 'Z' : case 'z':
-                       if (redzone)
-                               return 0;
-                       redzone = 1;
-                       break;
-
-               case 'U' : case 'u':
-                       if (tracking)
-                               return 0;
-                       tracking = 1;
-                       break;
-
-               case 'T' : case 't':
-                       if (tracing)
-                               return 0;
-                       tracing = 1;
-                       break;
-               default:
-                       return 0;
-               }
-       return 1;
-}
-
-static int slab_empty(struct slabinfo *s)
-{
-       if (s->objects > 0)
-               return 0;
-
-       /*
-        * We may still have slabs even if there are no objects. Shrinking will
-        * remove them.
-        */
-       if (s->slabs != 0)
-               set_obj(s, "shrink", 1);
-
-       return 1;
-}
-
-static void slab_debug(struct slabinfo *s)
-{
-       if (strcmp(s->name, "*") == 0)
-               return;
-
-       if (sanity && !s->sanity_checks) {
-               set_obj(s, "sanity", 1);
-       }
-       if (!sanity && s->sanity_checks) {
-               if (slab_empty(s))
-                       set_obj(s, "sanity", 0);
-               else
-                       fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
-       }
-       if (redzone && !s->red_zone) {
-               if (slab_empty(s))
-                       set_obj(s, "red_zone", 1);
-               else
-                       fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
-       }
-       if (!redzone && s->red_zone) {
-               if (slab_empty(s))
-                       set_obj(s, "red_zone", 0);
-               else
-                       fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
-       }
-       if (poison && !s->poison) {
-               if (slab_empty(s))
-                       set_obj(s, "poison", 1);
-               else
-                       fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
-       }
-       if (!poison && s->poison) {
-               if (slab_empty(s))
-                       set_obj(s, "poison", 0);
-               else
-                       fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
-       }
-       if (tracking && !s->store_user) {
-               if (slab_empty(s))
-                       set_obj(s, "store_user", 1);
-               else
-                       fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
-       }
-       if (!tracking && s->store_user) {
-               if (slab_empty(s))
-                       set_obj(s, "store_user", 0);
-               else
-                       fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
-       }
-       if (tracing && !s->trace) {
-               if (slabs == 1)
-                       set_obj(s, "trace", 1);
-               else
-                       fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
-       }
-       if (!tracing && s->trace)
-               set_obj(s, "trace", 1);
-}
-
-static void totals(void)
-{
-       struct slabinfo *s;
-
-       int used_slabs = 0;
-       char b1[20], b2[20], b3[20], b4[20];
-       unsigned long long max = 1ULL << 63;
-
-       /* Object size */
-       unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
-
-       /* Number of partial slabs in a slabcache */
-       unsigned long long min_partial = max, max_partial = 0,
-                               avg_partial, total_partial = 0;
-
-       /* Number of slabs in a slab cache */
-       unsigned long long min_slabs = max, max_slabs = 0,
-                               avg_slabs, total_slabs = 0;
-
-       /* Size of the whole slab */
-       unsigned long long min_size = max, max_size = 0,
-                               avg_size, total_size = 0;
-
-       /* Bytes used for object storage in a slab */
-       unsigned long long min_used = max, max_used = 0,
-                               avg_used, total_used = 0;
-
-       /* Waste: Bytes used for alignment and padding */
-       unsigned long long min_waste = max, max_waste = 0,
-                               avg_waste, total_waste = 0;
-       /* Number of objects in a slab */
-       unsigned long long min_objects = max, max_objects = 0,
-                               avg_objects, total_objects = 0;
-       /* Waste per object */
-       unsigned long long min_objwaste = max,
-                               max_objwaste = 0, avg_objwaste,
-                               total_objwaste = 0;
-
-       /* Memory per object */
-       unsigned long long min_memobj = max,
-                               max_memobj = 0, avg_memobj,
-                               total_objsize = 0;
-
-       /* Percentage of partial slabs per slab */
-       unsigned long min_ppart = 100, max_ppart = 0,
-                               avg_ppart, total_ppart = 0;
-
-       /* Number of objects in partial slabs */
-       unsigned long min_partobj = max, max_partobj = 0,
-                               avg_partobj, total_partobj = 0;
-
-       /* Percentage of partial objects of all objects in a slab */
-       unsigned long min_ppartobj = 100, max_ppartobj = 0,
-                               avg_ppartobj, total_ppartobj = 0;
-
-
-       for (s = slabinfo; s < slabinfo + slabs; s++) {
-               unsigned long long size;
-               unsigned long used;
-               unsigned long long wasted;
-               unsigned long long objwaste;
-               unsigned long percentage_partial_slabs;
-               unsigned long percentage_partial_objs;
-
-               if (!s->slabs || !s->objects)
-                       continue;
-
-               used_slabs++;
-
-               size = slab_size(s);
-               used = s->objects * s->object_size;
-               wasted = size - used;
-               objwaste = s->slab_size - s->object_size;
-
-               percentage_partial_slabs = s->partial * 100 / s->slabs;
-               if (percentage_partial_slabs > 100)
-                       percentage_partial_slabs = 100;
-
-               percentage_partial_objs = s->objects_partial * 100
-                                                       / s->objects;
-
-               if (percentage_partial_objs > 100)
-                       percentage_partial_objs = 100;
-
-               if (s->object_size < min_objsize)
-                       min_objsize = s->object_size;
-               if (s->partial < min_partial)
-                       min_partial = s->partial;
-               if (s->slabs < min_slabs)
-                       min_slabs = s->slabs;
-               if (size < min_size)
-                       min_size = size;
-               if (wasted < min_waste)
-                       min_waste = wasted;
-               if (objwaste < min_objwaste)
-                       min_objwaste = objwaste;
-               if (s->objects < min_objects)
-                       min_objects = s->objects;
-               if (used < min_used)
-                       min_used = used;
-               if (s->objects_partial < min_partobj)
-                       min_partobj = s->objects_partial;
-               if (percentage_partial_slabs < min_ppart)
-                       min_ppart = percentage_partial_slabs;
-               if (percentage_partial_objs < min_ppartobj)
-                       min_ppartobj = percentage_partial_objs;
-               if (s->slab_size < min_memobj)
-                       min_memobj = s->slab_size;
-
-               if (s->object_size > max_objsize)
-                       max_objsize = s->object_size;
-               if (s->partial > max_partial)
-                       max_partial = s->partial;
-               if (s->slabs > max_slabs)
-                       max_slabs = s->slabs;
-               if (size > max_size)
-                       max_size = size;
-               if (wasted > max_waste)
-                       max_waste = wasted;
-               if (objwaste > max_objwaste)
-                       max_objwaste = objwaste;
-               if (s->objects > max_objects)
-                       max_objects = s->objects;
-               if (used > max_used)
-                       max_used = used;
-               if (s->objects_partial > max_partobj)
-                       max_partobj = s->objects_partial;
-               if (percentage_partial_slabs > max_ppart)
-                       max_ppart = percentage_partial_slabs;
-               if (percentage_partial_objs > max_ppartobj)
-                       max_ppartobj = percentage_partial_objs;
-               if (s->slab_size > max_memobj)
-                       max_memobj = s->slab_size;
-
-               total_partial += s->partial;
-               total_slabs += s->slabs;
-               total_size += size;
-               total_waste += wasted;
-
-               total_objects += s->objects;
-               total_used += used;
-               total_partobj += s->objects_partial;
-               total_ppart += percentage_partial_slabs;
-               total_ppartobj += percentage_partial_objs;
-
-               total_objwaste += s->objects * objwaste;
-               total_objsize += s->objects * s->slab_size;
-       }
-
-       if (!total_objects) {
-               printf("No objects\n");
-               return;
-       }
-       if (!used_slabs) {
-               printf("No slabs\n");
-               return;
-       }
-
-       /* Per slab averages */
-       avg_partial = total_partial / used_slabs;
-       avg_slabs = total_slabs / used_slabs;
-       avg_size = total_size / used_slabs;
-       avg_waste = total_waste / used_slabs;
-
-       avg_objects = total_objects / used_slabs;
-       avg_used = total_used / used_slabs;
-       avg_partobj = total_partobj / used_slabs;
-       avg_ppart = total_ppart / used_slabs;
-       avg_ppartobj = total_ppartobj / used_slabs;
-
-       /* Per object object sizes */
-       avg_objsize = total_used / total_objects;
-       avg_objwaste = total_objwaste / total_objects;
-       avg_partobj = total_partobj * 100 / total_objects;
-       avg_memobj = total_objsize / total_objects;
-
-       printf("Slabcache Totals\n");
-       printf("----------------\n");
-       printf("Slabcaches : %3d      Aliases  : %3d->%-3d Active: %3d\n",
-                       slabs, aliases, alias_targets, used_slabs);
-
-       store_size(b1, total_size);store_size(b2, total_waste);
-       store_size(b3, total_waste * 100 / total_used);
-       printf("Memory used: %6s   # Loss   : %6s   MRatio:%6s%%\n", b1, b2, b3);
-
-       store_size(b1, total_objects);store_size(b2, total_partobj);
-       store_size(b3, total_partobj * 100 / total_objects);
-       printf("# Objects  : %6s   # PartObj: %6s   ORatio:%6s%%\n", b1, b2, b3);
-
-       printf("\n");
-       printf("Per Cache    Average         Min         Max       Total\n");
-       printf("---------------------------------------------------------\n");
-
-       store_size(b1, avg_objects);store_size(b2, min_objects);
-       store_size(b3, max_objects);store_size(b4, total_objects);
-       printf("#Objects  %10s  %10s  %10s  %10s\n",
-                       b1,     b2,     b3,     b4);
-
-       store_size(b1, avg_slabs);store_size(b2, min_slabs);
-       store_size(b3, max_slabs);store_size(b4, total_slabs);
-       printf("#Slabs    %10s  %10s  %10s  %10s\n",
-                       b1,     b2,     b3,     b4);
-
-       store_size(b1, avg_partial);store_size(b2, min_partial);
-       store_size(b3, max_partial);store_size(b4, total_partial);
-       printf("#PartSlab %10s  %10s  %10s  %10s\n",
-                       b1,     b2,     b3,     b4);
-       store_size(b1, avg_ppart);store_size(b2, min_ppart);
-       store_size(b3, max_ppart);
-       store_size(b4, total_partial * 100  / total_slabs);
-       printf("%%PartSlab%10s%% %10s%% %10s%% %10s%%\n",
-                       b1,     b2,     b3,     b4);
-
-       store_size(b1, avg_partobj);store_size(b2, min_partobj);
-       store_size(b3, max_partobj);
-       store_size(b4, total_partobj);
-       printf("PartObjs  %10s  %10s  %10s  %10s\n",
-                       b1,     b2,     b3,     b4);
-
-       store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
-       store_size(b3, max_ppartobj);
-       store_size(b4, total_partobj * 100 / total_objects);
-       printf("%% PartObj%10s%% %10s%% %10s%% %10s%%\n",
-                       b1,     b2,     b3,     b4);
-
-       store_size(b1, avg_size);store_size(b2, min_size);
-       store_size(b3, max_size);store_size(b4, total_size);
-       printf("Memory    %10s  %10s  %10s  %10s\n",
-                       b1,     b2,     b3,     b4);
-
-       store_size(b1, avg_used);store_size(b2, min_used);
-       store_size(b3, max_used);store_size(b4, total_used);
-       printf("Used      %10s  %10s  %10s  %10s\n",
-                       b1,     b2,     b3,     b4);
-
-       store_size(b1, avg_waste);store_size(b2, min_waste);
-       store_size(b3, max_waste);store_size(b4, total_waste);
-       printf("Loss      %10s  %10s  %10s  %10s\n",
-                       b1,     b2,     b3,     b4);
-
-       printf("\n");
-       printf("Per Object   Average         Min         Max\n");
-       printf("---------------------------------------------\n");
-
-       store_size(b1, avg_memobj);store_size(b2, min_memobj);
-       store_size(b3, max_memobj);
-       printf("Memory    %10s  %10s  %10s\n",
-                       b1,     b2,     b3);
-       store_size(b1, avg_objsize);store_size(b2, min_objsize);
-       store_size(b3, max_objsize);
-       printf("User      %10s  %10s  %10s\n",
-                       b1,     b2,     b3);
-
-       store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
-       store_size(b3, max_objwaste);
-       printf("Loss      %10s  %10s  %10s\n",
-                       b1,     b2,     b3);
-}
-
-static void sort_slabs(void)
-{
-       struct slabinfo *s1,*s2;
-
-       for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
-               for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
-                       int result;
-
-                       if (sort_size)
-                               result = slab_size(s1) < slab_size(s2);
-                       else if (sort_active)
-                               result = slab_activity(s1) < slab_activity(s2);
-                       else
-                               result = strcasecmp(s1->name, s2->name);
-
-                       if (show_inverted)
-                               result = -result;
-
-                       if (result > 0) {
-                               struct slabinfo t;
-
-                               memcpy(&t, s1, sizeof(struct slabinfo));
-                               memcpy(s1, s2, sizeof(struct slabinfo));
-                               memcpy(s2, &t, sizeof(struct slabinfo));
-                       }
-               }
-       }
-}
-
-static void sort_aliases(void)
-{
-       struct aliasinfo *a1,*a2;
-
-       for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
-               for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
-                       char *n1, *n2;
-
-                       n1 = a1->name;
-                       n2 = a2->name;
-                       if (show_alias && !show_inverted) {
-                               n1 = a1->ref;
-                               n2 = a2->ref;
-                       }
-                       if (strcasecmp(n1, n2) > 0) {
-                               struct aliasinfo t;
-
-                               memcpy(&t, a1, sizeof(struct aliasinfo));
-                               memcpy(a1, a2, sizeof(struct aliasinfo));
-                               memcpy(a2, &t, sizeof(struct aliasinfo));
-                       }
-               }
-       }
-}
-
-static void link_slabs(void)
-{
-       struct aliasinfo *a;
-       struct slabinfo *s;
-
-       for (a = aliasinfo; a < aliasinfo + aliases; a++) {
-
-               for (s = slabinfo; s < slabinfo + slabs; s++)
-                       if (strcmp(a->ref, s->name) == 0) {
-                               a->slab = s;
-                               s->refs++;
-                               break;
-                       }
-               if (s == slabinfo + slabs)
-                       fatal("Unresolved alias %s\n", a->ref);
-       }
-}
-
-static void alias(void)
-{
-       struct aliasinfo *a;
-       char *active = NULL;
-
-       sort_aliases();
-       link_slabs();
-
-       for(a = aliasinfo; a < aliasinfo + aliases; a++) {
-
-               if (!show_single_ref && a->slab->refs == 1)
-                       continue;
-
-               if (!show_inverted) {
-                       if (active) {
-                               if (strcmp(a->slab->name, active) == 0) {
-                                       printf(" %s", a->name);
-                                       continue;
-                               }
-                       }
-                       printf("\n%-12s <- %s", a->slab->name, a->name);
-                       active = a->slab->name;
-               }
-               else
-                       printf("%-20s -> %s\n", a->name, a->slab->name);
-       }
-       if (active)
-               printf("\n");
-}
-
-
-static void rename_slabs(void)
-{
-       struct slabinfo *s;
-       struct aliasinfo *a;
-
-       for (s = slabinfo; s < slabinfo + slabs; s++) {
-               if (*s->name != ':')
-                       continue;
-
-               if (s->refs > 1 && !show_first_alias)
-                       continue;
-
-               a = find_one_alias(s);
-
-               if (a)
-                       s->name = a->name;
-               else {
-                       s->name = "*";
-                       actual_slabs--;
-               }
-       }
-}
-
-static int slab_mismatch(char *slab)
-{
-       return regexec(&pattern, slab, 0, NULL, 0);
-}
-
-static void read_slab_dir(void)
-{
-       DIR *dir;
-       struct dirent *de;
-       struct slabinfo *slab = slabinfo;
-       struct aliasinfo *alias = aliasinfo;
-       char *p;
-       char *t;
-       int count;
-
-       if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
-               fatal("SYSFS support for SLUB not active\n");
-
-       dir = opendir(".");
-       while ((de = readdir(dir))) {
-               if (de->d_name[0] == '.' ||
-                       (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
-                               continue;
-               switch (de->d_type) {
-                  case DT_LNK:
-                       alias->name = strdup(de->d_name);
-                       count = readlink(de->d_name, buffer, sizeof(buffer));
-
-                       if (count < 0)
-                               fatal("Cannot read symlink %s\n", de->d_name);
-
-                       buffer[count] = 0;
-                       p = buffer + count;
-                       while (p > buffer && p[-1] != '/')
-                               p--;
-                       alias->ref = strdup(p);
-                       alias++;
-                       break;
-                  case DT_DIR:
-                       if (chdir(de->d_name))
-                               fatal("Unable to access slab %s\n", slab->name);
-                       slab->name = strdup(de->d_name);
-                       slab->alias = 0;
-                       slab->refs = 0;
-                       slab->aliases = get_obj("aliases");
-                       slab->align = get_obj("align");
-                       slab->cache_dma = get_obj("cache_dma");
-                       slab->cpu_slabs = get_obj("cpu_slabs");
-                       slab->destroy_by_rcu = get_obj("destroy_by_rcu");
-                       slab->hwcache_align = get_obj("hwcache_align");
-                       slab->object_size = get_obj("object_size");
-                       slab->objects = get_obj("objects");
-                       slab->objects_partial = get_obj("objects_partial");
-                       slab->objects_total = get_obj("objects_total");
-                       slab->objs_per_slab = get_obj("objs_per_slab");
-                       slab->order = get_obj("order");
-                       slab->partial = get_obj("partial");
-                       slab->partial = get_obj_and_str("partial", &t);
-                       decode_numa_list(slab->numa_partial, t);
-                       free(t);
-                       slab->poison = get_obj("poison");
-                       slab->reclaim_account = get_obj("reclaim_account");
-                       slab->red_zone = get_obj("red_zone");
-                       slab->sanity_checks = get_obj("sanity_checks");
-                       slab->slab_size = get_obj("slab_size");
-                       slab->slabs = get_obj_and_str("slabs", &t);
-                       decode_numa_list(slab->numa, t);
-                       free(t);
-                       slab->store_user = get_obj("store_user");
-                       slab->trace = get_obj("trace");
-                       slab->alloc_fastpath = get_obj("alloc_fastpath");
-                       slab->alloc_slowpath = get_obj("alloc_slowpath");
-                       slab->free_fastpath = get_obj("free_fastpath");
-                       slab->free_slowpath = get_obj("free_slowpath");
-                       slab->free_frozen= get_obj("free_frozen");
-                       slab->free_add_partial = get_obj("free_add_partial");
-                       slab->free_remove_partial = get_obj("free_remove_partial");
-                       slab->alloc_from_partial = get_obj("alloc_from_partial");
-                       slab->alloc_slab = get_obj("alloc_slab");
-                       slab->alloc_refill = get_obj("alloc_refill");
-                       slab->free_slab = get_obj("free_slab");
-                       slab->cpuslab_flush = get_obj("cpuslab_flush");
-                       slab->deactivate_full = get_obj("deactivate_full");
-                       slab->deactivate_empty = get_obj("deactivate_empty");
-                       slab->deactivate_to_head = get_obj("deactivate_to_head");
-                       slab->deactivate_to_tail = get_obj("deactivate_to_tail");
-                       slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
-                       slab->order_fallback = get_obj("order_fallback");
-                       chdir("..");
-                       if (slab->name[0] == ':')
-                               alias_targets++;
-                       slab++;
-                       break;
-                  default :
-                       fatal("Unknown file type %lx\n", de->d_type);
-               }
-       }
-       closedir(dir);
-       slabs = slab - slabinfo;
-       actual_slabs = slabs;
-       aliases = alias - aliasinfo;
-       if (slabs > MAX_SLABS)
-               fatal("Too many slabs\n");
-       if (aliases > MAX_ALIASES)
-               fatal("Too many aliases\n");
-}
-
-static void output_slabs(void)
-{
-       struct slabinfo *slab;
-
-       for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
-
-               if (slab->alias)
-                       continue;
-
-
-               if (show_numa)
-                       slab_numa(slab, 0);
-               else if (show_track)
-                       show_tracking(slab);
-               else if (validate)
-                       slab_validate(slab);
-               else if (shrink)
-                       slab_shrink(slab);
-               else if (set_debug)
-                       slab_debug(slab);
-               else if (show_ops)
-                       ops(slab);
-               else if (show_slab)
-                       slabcache(slab);
-               else if (show_report)
-                       report(slab);
-       }
-}
-
-struct option opts[] = {
-       { "aliases", 0, NULL, 'a' },
-       { "activity", 0, NULL, 'A' },
-       { "debug", 2, NULL, 'd' },
-       { "display-activity", 0, NULL, 'D' },
-       { "empty", 0, NULL, 'e' },
-       { "first-alias", 0, NULL, 'f' },
-       { "help", 0, NULL, 'h' },
-       { "inverted", 0, NULL, 'i'},
-       { "numa", 0, NULL, 'n' },
-       { "ops", 0, NULL, 'o' },
-       { "report", 0, NULL, 'r' },
-       { "shrink", 0, NULL, 's' },
-       { "slabs", 0, NULL, 'l' },
-       { "track", 0, NULL, 't'},
-       { "validate", 0, NULL, 'v' },
-       { "zero", 0, NULL, 'z' },
-       { "1ref", 0, NULL, '1'},
-       { NULL, 0, NULL, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       int c;
-       int err;
-       char *pattern_source;
-
-       page_size = getpagesize();
-
-       while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS",
-                                               opts, NULL)) != -1)
-               switch (c) {
-               case '1':
-                       show_single_ref = 1;
-                       break;
-               case 'a':
-                       show_alias = 1;
-                       break;
-               case 'A':
-                       sort_active = 1;
-                       break;
-               case 'd':
-                       set_debug = 1;
-                       if (!debug_opt_scan(optarg))
-                               fatal("Invalid debug option '%s'\n", optarg);
-                       break;
-               case 'D':
-                       show_activity = 1;
-                       break;
-               case 'e':
-                       show_empty = 1;
-                       break;
-               case 'f':
-                       show_first_alias = 1;
-                       break;
-               case 'h':
-                       usage();
-                       return 0;
-               case 'i':
-                       show_inverted = 1;
-                       break;
-               case 'n':
-                       show_numa = 1;
-                       break;
-               case 'o':
-                       show_ops = 1;
-                       break;
-               case 'r':
-                       show_report = 1;
-                       break;
-               case 's':
-                       shrink = 1;
-                       break;
-               case 'l':
-                       show_slab = 1;
-                       break;
-               case 't':
-                       show_track = 1;
-                       break;
-               case 'v':
-                       validate = 1;
-                       break;
-               case 'z':
-                       skip_zero = 0;
-                       break;
-               case 'T':
-                       show_totals = 1;
-                       break;
-               case 'S':
-                       sort_size = 1;
-                       break;
-
-               default:
-                       fatal("%s: Invalid option '%c'\n", argv[0], optopt);
-
-       }
-
-       if (!show_slab && !show_alias && !show_track && !show_report
-               && !validate && !shrink && !set_debug && !show_ops)
-                       show_slab = 1;
-
-       if (argc > optind)
-               pattern_source = argv[optind];
-       else
-               pattern_source = ".*";
-
-       err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
-       if (err)
-               fatal("%s: Invalid pattern '%s' code %d\n",
-                       argv[0], pattern_source, err);
-       read_slab_dir();
-       if (show_alias)
-               alias();
-       else
-       if (show_totals)
-               totals();
-       else {
-               link_slabs();
-               rename_slabs();
-               sort_slabs();
-               output_slabs();
-       }
-       return 0;
-}
index 48593dd..9e4d4ca 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/
index 74b2555..6a45769 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 1ecc15b..25a8fc7 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 387d5ff..5f5018a 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 be01d78..4c4e58e 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 bdc3831..2e72af0 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 99d9b61..9ae24f4 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 0a9b5b8..f489ec3 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 e625e9e..48fb479 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 fae8192..96deec6 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 9bb3d72..2a56a0d 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 dd38608..ad3a4f4 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 8e9be6b..27bd267 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 cad9c38..71d3bb4 100644 (file)
                        };
 
                        IIC: i2c@ef600500 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                compatible = "ibm,iic-405ep", "ibm,iic";
                                reg = <0xef600500 0x00000011>;
                                interrupt-parent = <&UIC0>;
index 59702ac..fb288bb 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 0c3902b..48d72f3 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 6ca4fc1..0b78e89 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 b72a758..21d3472 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 8a4ec30..9e35499 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 85d857a..1dd478b 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 019264c..ba83d54 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 ae26f2e..d727575 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 88334af..c2b7a07 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 546bbc2..2521d93 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 e487eb0..926731f 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 de55bc0..01ffa64 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 0bac3a3..2c7780c 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 d45be5b..e36d6e2 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 846831d..661d354 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 ae525e4..b54cd73 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 910caa6..7bafbf2 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 8f29bbc..5e847d0 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 15e13b5..23982c7 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 1398bc4..feaee40 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 d4d15aa..c2d675b 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 35f4883..8505e0a 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 a4446c0..82281a5 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 d342dba..0a601b3 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 9c6ac4b..5016c5e 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 bc8e4cb..f30e8d0 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 d936600..92204c3 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 ff2546c..7a15153 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 396ff4c..66d0fff 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 79e6baa..a51345b 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;
 
@@ -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 aa8c89a..7e8d3bc 100644 (file)
@@ -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 36e2319..c6b298d 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 2b67c90..27291aa 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 329cbbb..3e606c3 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 ebc08d6..26d4523 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 66aa4be..5defc74 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 7688868..d7e57db 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 9ae4c08..efdd18b 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",
@@ -302,6 +308,22 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long 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 32f3463..d2239bb 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++;
@@ -113,6 +113,22 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
 }
 
 /**
+ *     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 6ed6454..7613592 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 81f2c84..42f97f9 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 ead3e79..2a52270 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 02c652b..656493a 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)
 {
@@ -1078,6 +1084,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.
  * @old_delay: The former autosuspend_delay value.
@@ -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 71c5528..8ec406d 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 035da9e..f27c04e 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 4be62ed..e8c52c8 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 40a222e..68f942c 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 14bb7b7..48ae712 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 b42a0bd..d00f8ce 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 e6239f9..f8dfcf1 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 1a467a9..c2e194c 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 bf184fb..0618145 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 e3c8b60..d77d120 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 401acec..ffbc278 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 c335605..6eae9a9 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 4fb7c75..5243ae2 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 1666c16..902d1df 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 eaeca56..61aa712 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 f42ee14..e5b961d 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 4ce7aa3..a1a765a 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 5925bdc..375b509 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 e880086..888ece6 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 3f9673d..2611686 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 4cd0e23..2f0be4c 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 75c5e23..555382f 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 968b04f..afcf3d6 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 8fbff23..03bee19 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 6e31f30..79d0c61 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 88dfcf4..279ba53 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 8e11af8..f65cace 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 d8d372b..e60fdb8 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 817247e..f2ba9ef 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 b629fba..aef4104 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 4258253..3c31bc6 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 4002832..f98644c 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 7eef5a2..fa550c8 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 61142b7..90d0ef2 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 e6dc151..698e645 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 dc618c3..0f6fc54 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 c95c31e..dedf757 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 ac5421d..9fb050c 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 69169ef..beb4034 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 2e79716..e90edfc 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 308d6ae..f1ea3ff 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 bc2e077..de9cf21 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 9f41e2b..06e5300 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 48eab84..ab19f29 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 54d3db5..87a54df 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 f776957..cbd8cc4 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 130d656..64abb5b 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 9bf2304..02c58e0 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 22f80a8..14cbbe1 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 5a6879e..a14c579 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 09e864e..5784281 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 3589444..3c1fd8a 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 e10a768..16f7caf 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 677bb3d..68d7b36 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 3171be2..b2be1d1 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 164ed56..d484a00 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 25be4e1..575862b 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 956ed9a..613ff7b 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 724f46e..0688832 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 b7accea..f31fab0 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 aac1f92..e903715 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 e1f0748..468e87b 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 1329ecb..db3cf31 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 5489eab..b336dd8 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 ef381d7..f91c136 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 2c18547..76b9a14 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 984feb3..af0a7c1 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 89d2e84..1673cac 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 a948605..0658173 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 a56f6ad..bdc13d2 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 2479b3d..dde02d9 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 03694cc..8f07a9d 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 3cf28af..48d21e2 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 87d92a5..c6d1ce0 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 b6598aa..ce0372f 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, s16* value)
+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 7dada55..c02a052 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 23b8555..2d68cf3 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 42de98d..194ca0a 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 980c17d..e9a610b 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 525a00b..92f9497 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 75afb3b..3f49dd3 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 a56a784..3d21fa2 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 2b2ca16..2582bfe 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 29ea675..a61e781 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 eaee546..bc6e2ab 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 0cee73a..1b674b7 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 fd108cf..3b84fb5 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 4546d82..1a6dfb6 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 dc7259d..731b09a 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 0798210..21c817d 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 79c2931..47d7ce9 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 f46d936..9fb7516 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 8fa462f..f44a89a 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 ec7fad7..0d18de4 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 f397ce7..13e8d21 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 ae33bbb..49163d4 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 e6078c9..db3b2e8 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 072c580..073eabe 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 38e2805..bde50e3 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 b952317..ee82851 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 559b0b3..ab1ad41 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 d618e86..e960a93 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 c51b711..fa19d84 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 1e2cbf5..b1f7689 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 a0dd7bb..5d37d31 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 4da384c..31fe980 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 d684f18..7a1f3d0 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 45c4b7b..6de4675 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 acbdab3..73a3e0d 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 de6c308..cad66ce 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 aa675eb..3c6e100 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 7888155..3ab21a0 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 3a1c7e7..b4559c5 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 c1360e0..c787c3d 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 1fce00e..dcd7857 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 5b4a07f..c01cd1a 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 bab5204..7722108 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 2ea9cf1..b283bbe 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 707b7f4..9e32780 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 a624f5a..e856622 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 de2e09e..d3c5905 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 29251fa..5815cbe 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 ec3c214..188aff6 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 17849dc..5c7abe4 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 3f5e387..5f63c3b 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 b02d0cb..34bb17f 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 b9278a1..fca6172 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 9e8639d..b0176e4 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 4abb0b9..3e6934d 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 65f8637..7468147 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;
 }
 
@@ -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);
index 224d7bb..e654dfd 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 103ab8b..ede9830 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 8704490..4dfba82 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 f856732..66f3d50 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 8e21e0f..5e7075d 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 7136c0c..606ca8b 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 67acfb3..2f6795e 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 cc1a860..a65d311 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 db2a58c..2e77382 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 5a28660..d843631 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 a853a89..0c7e369 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 ec5b68e..76b1b37 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 7b01d3f..eb74648 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 e0588cd..59ca81b 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 37a34c2..9c64ae9 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 6e07696..cf8d28d 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 f738599..042af73 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 8b984a2..95da1bc 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 57d4a3a..ae5744a 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
@@ -656,11 +670,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
  */
 void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req);
index a8b31da..f62b32c 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 8d3d2b4..a79790c 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 19433cd..24ece10 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 8b782b0..3ee67c6 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 5115814..388e9e8 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 cb003c8..9d45773 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 c9a30d7..2f560c9 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 9f8a2da..bfc73d3 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 77b48c8..2fd440d 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 b185e93..4967389 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 39a5b84..6a0e2a1 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 6e9557e..9803427 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 0ca9882..777e8fd 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 a6c3c2e..0c43241 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 fb9e8a8..622df27 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 5d2711c..3dfcd3b 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 35a0715..7a17715 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 687d090..55ebae5 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 e2dcc9c..70dfdd5 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 0254be2..ad4ac60 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 69226e1..fd85e4c 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 30ac273..0a12eb8 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 ffaaa81..3d28af3 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/lockdep.h>
+#include <linux/kobject_ns.h>
 #include <linux/fs.h>
 
 struct sysfs_open_dirent;
index bd69d79..05cbad0 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)                                                   \
index a354c19..d1580c1 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 8b5c062..359df04 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 bd07758..59fcd24 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 24c806f..5ac3bdd 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 dd48953..d96af97 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 1cd637e..9a3f5f9 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 c6dcc1d..43fe52f 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 baf3e55..f84d992 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 c3c578e..d464de5 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 bb0f56f..20b9801 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 330586f..f376ddc 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 d947b12..c9c5d7a 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 8aea06f..2feda6e 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 7bbf5b3..0ef22a1 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 bb27d7e..77257c9 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 40f3f45..dd9c7ab 100644 (file)
@@ -367,45 +367,6 @@ extern struct dev_pm_ops generic_subsys_pm_ops;
                                        { .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.
  *
  * These status labels are used internally by the PM core to indicate the
@@ -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 d19f1cc..d34f067 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);
index 341acbb..abc527a 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 791a502..83203ae 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 e4f5ed1..8b6e8ae 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 6950c98..78aa104 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 2669751..144b34b 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 0b5ff08..33e0a39 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 bd1d42b..66ecd2e 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 f9063c6..b755972 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 048d0b5..870f72b 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 e50b4c1..d6d2a10 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 031d5e3..8850df6 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 e9f9298..2640374 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -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 a2fe172..008cd74 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 c5d5db5..e2741d2 100644 (file)
@@ -7,3 +7,4 @@ pnmtologo
 bin2c
 unifdef
 ihex2fw
+recordmcount
index 4c72c11..396da16 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 ea26b23..c9a16ab 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 6bb42e7..3ab316e 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 55d7dc1..156b20a 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 9969d76..cdac6cf 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 608d7fd..a7c7c4b 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 01cdb36..04a31c1 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 9548579..a662a00 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 a627bbe..e866ea5 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 e27cc63..50c4420 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 2712937..9be2eea 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 ba99100..95c9547 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 b2ab562..5e84a67 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 d8fd43b..cbc0193 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 08d54c8..f37c97e 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 76acd28..ead0332 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 8fe1bdf..f377453 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 0ca3de5..c9209d5 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 9641b76..2dbc874 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 e17c7c0..bd7966e 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 1521ff1..c09aafa 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 658ff42..6158b86 100644 (file)
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.2.0"
+#define DTC_VERSION "DTC 1.2.0-g37c0b6a0"
index eaee44e..809b949 100644 (file)
 
 
 #include <assert.h>
-#include <malloc.h>
+#include <stdlib.h>
 #include "genksyms.h"
 
 static int is_typedef;
index 10d7dc7..09a265c 100644 (file)
@@ -24,7 +24,7 @@
 %{
 
 #include <assert.h>
-#include <malloc.h>
+#include <stdlib.h>
 #include "genksyms.h"
 
 static int is_typedef;
index 1ddcdd3..978b42b 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 50d6cfd..7957e7a 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 4ca3be3..efb3be1 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 5459a38..659326c 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 9df8011..61c35bf 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 330e7c0..0010034 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 e57826c..3d238db 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 3f7240d..febf0c9 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 5f77dcb..5fdf10d 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 272a987..db56377 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 af6e9f3..a796c95 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 2e3d3cd..446739c 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 33122ca..97d2259 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 49b74e1..b0b2357 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 bbbe584..92fdc45 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 be36fea..ab8c6d8 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 734a6d3..19ba16e 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 e94e82f..5615081 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"
diff --git a/tools/slub/slabinfo.c b/tools/slub/slabinfo.c
new file mode 100644 (file)
index 0000000..516551c
--- /dev/null
@@ -0,0 +1,1364 @@
+/*
+ * Slabinfo: Tool to get reports about slabs
+ *
+ * (C) 2007 sgi, Christoph Lameter
+ *
+ * Compile by:
+ *
+ * gcc -o slabinfo slabinfo.c
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <strings.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <regex.h>
+#include <errno.h>
+
+#define MAX_SLABS 500
+#define MAX_ALIASES 500
+#define MAX_NODES 1024
+
+struct slabinfo {
+       char *name;
+       int alias;
+       int refs;
+       int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
+       int hwcache_align, object_size, objs_per_slab;
+       int sanity_checks, slab_size, store_user, trace;
+       int order, poison, reclaim_account, red_zone;
+       unsigned long partial, objects, slabs, objects_partial, objects_total;
+       unsigned long alloc_fastpath, alloc_slowpath;
+       unsigned long free_fastpath, free_slowpath;
+       unsigned long free_frozen, free_add_partial, free_remove_partial;
+       unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
+       unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
+       unsigned long deactivate_to_head, deactivate_to_tail;
+       unsigned long deactivate_remote_frees, order_fallback;
+       int numa[MAX_NODES];
+       int numa_partial[MAX_NODES];
+} slabinfo[MAX_SLABS];
+
+struct aliasinfo {
+       char *name;
+       char *ref;
+       struct slabinfo *slab;
+} aliasinfo[MAX_ALIASES];
+
+int slabs = 0;
+int actual_slabs = 0;
+int aliases = 0;
+int alias_targets = 0;
+int highest_node = 0;
+
+char buffer[4096];
+
+int show_empty = 0;
+int show_report = 0;
+int show_alias = 0;
+int show_slab = 0;
+int skip_zero = 1;
+int show_numa = 0;
+int show_track = 0;
+int show_first_alias = 0;
+int validate = 0;
+int shrink = 0;
+int show_inverted = 0;
+int show_single_ref = 0;
+int show_totals = 0;
+int sort_size = 0;
+int sort_active = 0;
+int set_debug = 0;
+int show_ops = 0;
+int show_activity = 0;
+
+/* Debug options */
+int sanity = 0;
+int redzone = 0;
+int poison = 0;
+int tracking = 0;
+int tracing = 0;
+
+int page_size;
+
+regex_t pattern;
+
+static void fatal(const char *x, ...)
+{
+       va_list ap;
+
+       va_start(ap, x);
+       vfprintf(stderr, x, ap);
+       va_end(ap);
+       exit(EXIT_FAILURE);
+}
+
+static void usage(void)
+{
+       printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n"
+               "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
+               "-a|--aliases           Show aliases\n"
+               "-A|--activity          Most active slabs first\n"
+               "-d<options>|--debug=<options> Set/Clear Debug options\n"
+               "-D|--display-active    Switch line format to activity\n"
+               "-e|--empty             Show empty slabs\n"
+               "-f|--first-alias       Show first alias\n"
+               "-h|--help              Show usage information\n"
+               "-i|--inverted          Inverted list\n"
+               "-l|--slabs             Show slabs\n"
+               "-n|--numa              Show NUMA information\n"
+               "-o|--ops               Show kmem_cache_ops\n"
+               "-s|--shrink            Shrink slabs\n"
+               "-r|--report            Detailed report on single slabs\n"
+               "-S|--Size              Sort by size\n"
+               "-t|--tracking          Show alloc/free information\n"
+               "-T|--Totals            Show summary information\n"
+               "-v|--validate          Validate slabs\n"
+               "-z|--zero              Include empty slabs\n"
+               "-1|--1ref              Single reference\n"
+               "\nValid debug options (FZPUT may be combined)\n"
+               "a / A          Switch on all debug options (=FZUP)\n"
+               "-              Switch off all debug options\n"
+               "f / F          Sanity Checks (SLAB_DEBUG_FREE)\n"
+               "z / Z          Redzoning\n"
+               "p / P          Poisoning\n"
+               "u / U          Tracking\n"
+               "t / T          Tracing\n"
+       );
+}
+
+static unsigned long read_obj(const char *name)
+{
+       FILE *f = fopen(name, "r");
+
+       if (!f)
+               buffer[0] = 0;
+       else {
+               if (!fgets(buffer, sizeof(buffer), f))
+                       buffer[0] = 0;
+               fclose(f);
+               if (buffer[strlen(buffer)] == '\n')
+                       buffer[strlen(buffer)] = 0;
+       }
+       return strlen(buffer);
+}
+
+
+/*
+ * Get the contents of an attribute
+ */
+static unsigned long get_obj(const char *name)
+{
+       if (!read_obj(name))
+               return 0;
+
+       return atol(buffer);
+}
+
+static unsigned long get_obj_and_str(const char *name, char **x)
+{
+       unsigned long result = 0;
+       char *p;
+
+       *x = NULL;
+
+       if (!read_obj(name)) {
+               x = NULL;
+               return 0;
+       }
+       result = strtoul(buffer, &p, 10);
+       while (*p == ' ')
+               p++;
+       if (*p)
+               *x = strdup(p);
+       return result;
+}
+
+static void set_obj(struct slabinfo *s, const char *name, int n)
+{
+       char x[100];
+       FILE *f;
+
+       snprintf(x, 100, "%s/%s", s->name, name);
+       f = fopen(x, "w");
+       if (!f)
+               fatal("Cannot write to %s\n", x);
+
+       fprintf(f, "%d\n", n);
+       fclose(f);
+}
+
+static unsigned long read_slab_obj(struct slabinfo *s, const char *name)
+{
+       char x[100];
+       FILE *f;
+       size_t l;
+
+       snprintf(x, 100, "%s/%s", s->name, name);
+       f = fopen(x, "r");
+       if (!f) {
+               buffer[0] = 0;
+               l = 0;
+       } else {
+               l = fread(buffer, 1, sizeof(buffer), f);
+               buffer[l] = 0;
+               fclose(f);
+       }
+       return l;
+}
+
+
+/*
+ * Put a size string together
+ */
+static int store_size(char *buffer, unsigned long value)
+{
+       unsigned long divisor = 1;
+       char trailer = 0;
+       int n;
+
+       if (value > 1000000000UL) {
+               divisor = 100000000UL;
+               trailer = 'G';
+       } else if (value > 1000000UL) {
+               divisor = 100000UL;
+               trailer = 'M';
+       } else if (value > 1000UL) {
+               divisor = 100;
+               trailer = 'K';
+       }
+
+       value /= divisor;
+       n = sprintf(buffer, "%ld",value);
+       if (trailer) {
+               buffer[n] = trailer;
+               n++;
+               buffer[n] = 0;
+       }
+       if (divisor != 1) {
+               memmove(buffer + n - 2, buffer + n - 3, 4);
+               buffer[n-2] = '.';
+               n++;
+       }
+       return n;
+}
+
+static void decode_numa_list(int *numa, char *t)
+{
+       int node;
+       int nr;
+
+       memset(numa, 0, MAX_NODES * sizeof(int));
+
+       if (!t)
+               return;
+
+       while (*t == 'N') {
+               t++;
+               node = strtoul(t, &t, 10);
+               if (*t == '=') {
+                       t++;
+                       nr = strtoul(t, &t, 10);
+                       numa[node] = nr;
+                       if (node > highest_node)
+                               highest_node = node;
+               }
+               while (*t == ' ')
+                       t++;
+       }
+}
+
+static void slab_validate(struct slabinfo *s)
+{
+       if (strcmp(s->name, "*") == 0)
+               return;
+
+       set_obj(s, "validate", 1);
+}
+
+static void slab_shrink(struct slabinfo *s)
+{
+       if (strcmp(s->name, "*") == 0)
+               return;
+
+       set_obj(s, "shrink", 1);
+}
+
+int line = 0;
+
+static void first_line(void)
+{
+       if (show_activity)
+               printf("Name                   Objects      Alloc       Free   %%Fast Fallb O\n");
+       else
+               printf("Name                   Objects Objsize    Space "
+                       "Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
+}
+
+/*
+ * Find the shortest alias of a slab
+ */
+static struct aliasinfo *find_one_alias(struct slabinfo *find)
+{
+       struct aliasinfo *a;
+       struct aliasinfo *best = NULL;
+
+       for(a = aliasinfo;a < aliasinfo + aliases; a++) {
+               if (a->slab == find &&
+                       (!best || strlen(best->name) < strlen(a->name))) {
+                               best = a;
+                               if (strncmp(a->name,"kmall", 5) == 0)
+                                       return best;
+                       }
+       }
+       return best;
+}
+
+static unsigned long slab_size(struct slabinfo *s)
+{
+       return  s->slabs * (page_size << s->order);
+}
+
+static unsigned long slab_activity(struct slabinfo *s)
+{
+       return  s->alloc_fastpath + s->free_fastpath +
+               s->alloc_slowpath + s->free_slowpath;
+}
+
+static void slab_numa(struct slabinfo *s, int mode)
+{
+       int node;
+
+       if (strcmp(s->name, "*") == 0)
+               return;
+
+       if (!highest_node) {
+               printf("\n%s: No NUMA information available.\n", s->name);
+               return;
+       }
+
+       if (skip_zero && !s->slabs)
+               return;
+
+       if (!line) {
+               printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
+               for(node = 0; node <= highest_node; node++)
+                       printf(" %4d", node);
+               printf("\n----------------------");
+               for(node = 0; node <= highest_node; node++)
+                       printf("-----");
+               printf("\n");
+       }
+       printf("%-21s ", mode ? "All slabs" : s->name);
+       for(node = 0; node <= highest_node; node++) {
+               char b[20];
+
+               store_size(b, s->numa[node]);
+               printf(" %4s", b);
+       }
+       printf("\n");
+       if (mode) {
+               printf("%-21s ", "Partial slabs");
+               for(node = 0; node <= highest_node; node++) {
+                       char b[20];
+
+                       store_size(b, s->numa_partial[node]);
+                       printf(" %4s", b);
+               }
+               printf("\n");
+       }
+       line++;
+}
+
+static void show_tracking(struct slabinfo *s)
+{
+       printf("\n%s: Kernel object allocation\n", s->name);
+       printf("-----------------------------------------------------------------------\n");
+       if (read_slab_obj(s, "alloc_calls"))
+               printf(buffer);
+       else
+               printf("No Data\n");
+
+       printf("\n%s: Kernel object freeing\n", s->name);
+       printf("------------------------------------------------------------------------\n");
+       if (read_slab_obj(s, "free_calls"))
+               printf(buffer);
+       else
+               printf("No Data\n");
+
+}
+
+static void ops(struct slabinfo *s)
+{
+       if (strcmp(s->name, "*") == 0)
+               return;
+
+       if (read_slab_obj(s, "ops")) {
+               printf("\n%s: kmem_cache operations\n", s->name);
+               printf("--------------------------------------------\n");
+               printf(buffer);
+       } else
+               printf("\n%s has no kmem_cache operations\n", s->name);
+}
+
+static const char *onoff(int x)
+{
+       if (x)
+               return "On ";
+       return "Off";
+}
+
+static void slab_stats(struct slabinfo *s)
+{
+       unsigned long total_alloc;
+       unsigned long total_free;
+       unsigned long total;
+
+       if (!s->alloc_slab)
+               return;
+
+       total_alloc = s->alloc_fastpath + s->alloc_slowpath;
+       total_free = s->free_fastpath + s->free_slowpath;
+
+       if (!total_alloc)
+               return;
+
+       printf("\n");
+       printf("Slab Perf Counter       Alloc     Free %%Al %%Fr\n");
+       printf("--------------------------------------------------\n");
+       printf("Fastpath             %8lu %8lu %3lu %3lu\n",
+               s->alloc_fastpath, s->free_fastpath,
+               s->alloc_fastpath * 100 / total_alloc,
+               s->free_fastpath * 100 / total_free);
+       printf("Slowpath             %8lu %8lu %3lu %3lu\n",
+               total_alloc - s->alloc_fastpath, s->free_slowpath,
+               (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
+               s->free_slowpath * 100 / total_free);
+       printf("Page Alloc           %8lu %8lu %3lu %3lu\n",
+               s->alloc_slab, s->free_slab,
+               s->alloc_slab * 100 / total_alloc,
+               s->free_slab * 100 / total_free);
+       printf("Add partial          %8lu %8lu %3lu %3lu\n",
+               s->deactivate_to_head + s->deactivate_to_tail,
+               s->free_add_partial,
+               (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
+               s->free_add_partial * 100 / total_free);
+       printf("Remove partial       %8lu %8lu %3lu %3lu\n",
+               s->alloc_from_partial, s->free_remove_partial,
+               s->alloc_from_partial * 100 / total_alloc,
+               s->free_remove_partial * 100 / total_free);
+
+       printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
+               s->deactivate_remote_frees, s->free_frozen,
+               s->deactivate_remote_frees * 100 / total_alloc,
+               s->free_frozen * 100 / total_free);
+
+       printf("Total                %8lu %8lu\n\n", total_alloc, total_free);
+
+       if (s->cpuslab_flush)
+               printf("Flushes %8lu\n", s->cpuslab_flush);
+
+       if (s->alloc_refill)
+               printf("Refill %8lu\n", s->alloc_refill);
+
+       total = s->deactivate_full + s->deactivate_empty +
+                       s->deactivate_to_head + s->deactivate_to_tail;
+
+       if (total)
+               printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) "
+                       "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n",
+                       s->deactivate_full, (s->deactivate_full * 100) / total,
+                       s->deactivate_empty, (s->deactivate_empty * 100) / total,
+                       s->deactivate_to_head, (s->deactivate_to_head * 100) / total,
+                       s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
+}
+
+static void report(struct slabinfo *s)
+{
+       if (strcmp(s->name, "*") == 0)
+               return;
+
+       printf("\nSlabcache: %-20s  Aliases: %2d Order : %2d Objects: %lu\n",
+               s->name, s->aliases, s->order, s->objects);
+       if (s->hwcache_align)
+               printf("** Hardware cacheline aligned\n");
+       if (s->cache_dma)
+               printf("** Memory is allocated in a special DMA zone\n");
+       if (s->destroy_by_rcu)
+               printf("** Slabs are destroyed via RCU\n");
+       if (s->reclaim_account)
+               printf("** Reclaim accounting active\n");
+
+       printf("\nSizes (bytes)     Slabs              Debug                Memory\n");
+       printf("------------------------------------------------------------------------\n");
+       printf("Object : %7d  Total  : %7ld   Sanity Checks : %s  Total: %7ld\n",
+                       s->object_size, s->slabs, onoff(s->sanity_checks),
+                       s->slabs * (page_size << s->order));
+       printf("SlabObj: %7d  Full   : %7ld   Redzoning     : %s  Used : %7ld\n",
+                       s->slab_size, s->slabs - s->partial - s->cpu_slabs,
+                       onoff(s->red_zone), s->objects * s->object_size);
+       printf("SlabSiz: %7d  Partial: %7ld   Poisoning     : %s  Loss : %7ld\n",
+                       page_size << s->order, s->partial, onoff(s->poison),
+                       s->slabs * (page_size << s->order) - s->objects * s->object_size);
+       printf("Loss   : %7d  CpuSlab: %7d   Tracking      : %s  Lalig: %7ld\n",
+                       s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
+                       (s->slab_size - s->object_size) * s->objects);
+       printf("Align  : %7d  Objects: %7d   Tracing       : %s  Lpadd: %7ld\n",
+                       s->align, s->objs_per_slab, onoff(s->trace),
+                       ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
+                       s->slabs);
+
+       ops(s);
+       show_tracking(s);
+       slab_numa(s, 1);
+       slab_stats(s);
+}
+
+static void slabcache(struct slabinfo *s)
+{
+       char size_str[20];
+       char dist_str[40];
+       char flags[20];
+       char *p = flags;
+
+       if (strcmp(s->name, "*") == 0)
+               return;
+
+       if (actual_slabs == 1) {
+               report(s);
+               return;
+       }
+
+       if (skip_zero && !show_empty && !s->slabs)
+               return;
+
+       if (show_empty && s->slabs)
+               return;
+
+       store_size(size_str, slab_size(s));
+       snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs,
+                                               s->partial, s->cpu_slabs);
+
+       if (!line++)
+               first_line();
+
+       if (s->aliases)
+               *p++ = '*';
+       if (s->cache_dma)
+               *p++ = 'd';
+       if (s->hwcache_align)
+               *p++ = 'A';
+       if (s->poison)
+               *p++ = 'P';
+       if (s->reclaim_account)
+               *p++ = 'a';
+       if (s->red_zone)
+               *p++ = 'Z';
+       if (s->sanity_checks)
+               *p++ = 'F';
+       if (s->store_user)
+               *p++ = 'U';
+       if (s->trace)
+               *p++ = 'T';
+
+       *p = 0;
+       if (show_activity) {
+               unsigned long total_alloc;
+               unsigned long total_free;
+
+               total_alloc = s->alloc_fastpath + s->alloc_slowpath;
+               total_free = s->free_fastpath + s->free_slowpath;
+
+               printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d\n",
+                       s->name, s->objects,
+                       total_alloc, total_free,
+                       total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
+                       total_free ? (s->free_fastpath * 100 / total_free) : 0,
+                       s->order_fallback, s->order);
+       }
+       else
+               printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
+                       s->name, s->objects, s->object_size, size_str, dist_str,
+                       s->objs_per_slab, s->order,
+                       s->slabs ? (s->partial * 100) / s->slabs : 100,
+                       s->slabs ? (s->objects * s->object_size * 100) /
+                               (s->slabs * (page_size << s->order)) : 100,
+                       flags);
+}
+
+/*
+ * Analyze debug options. Return false if something is amiss.
+ */
+static int debug_opt_scan(char *opt)
+{
+       if (!opt || !opt[0] || strcmp(opt, "-") == 0)
+               return 1;
+
+       if (strcasecmp(opt, "a") == 0) {
+               sanity = 1;
+               poison = 1;
+               redzone = 1;
+               tracking = 1;
+               return 1;
+       }
+
+       for ( ; *opt; opt++)
+               switch (*opt) {
+               case 'F' : case 'f':
+                       if (sanity)
+                               return 0;
+                       sanity = 1;
+                       break;
+               case 'P' : case 'p':
+                       if (poison)
+                               return 0;
+                       poison = 1;
+                       break;
+
+               case 'Z' : case 'z':
+                       if (redzone)
+                               return 0;
+                       redzone = 1;
+                       break;
+
+               case 'U' : case 'u':
+                       if (tracking)
+                               return 0;
+                       tracking = 1;
+                       break;
+
+               case 'T' : case 't':
+                       if (tracing)
+                               return 0;
+                       tracing = 1;
+                       break;
+               default:
+                       return 0;
+               }
+       return 1;
+}
+
+static int slab_empty(struct slabinfo *s)
+{
+       if (s->objects > 0)
+               return 0;
+
+       /*
+        * We may still have slabs even if there are no objects. Shrinking will
+        * remove them.
+        */
+       if (s->slabs != 0)
+               set_obj(s, "shrink", 1);
+
+       return 1;
+}
+
+static void slab_debug(struct slabinfo *s)
+{
+       if (strcmp(s->name, "*") == 0)
+               return;
+
+       if (sanity && !s->sanity_checks) {
+               set_obj(s, "sanity", 1);
+       }
+       if (!sanity && s->sanity_checks) {
+               if (slab_empty(s))
+                       set_obj(s, "sanity", 0);
+               else
+                       fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
+       }
+       if (redzone && !s->red_zone) {
+               if (slab_empty(s))
+                       set_obj(s, "red_zone", 1);
+               else
+                       fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
+       }
+       if (!redzone && s->red_zone) {
+               if (slab_empty(s))
+                       set_obj(s, "red_zone", 0);
+               else
+                       fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
+       }
+       if (poison && !s->poison) {
+               if (slab_empty(s))
+                       set_obj(s, "poison", 1);
+               else
+                       fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
+       }
+       if (!poison && s->poison) {
+               if (slab_empty(s))
+                       set_obj(s, "poison", 0);
+               else
+                       fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
+       }
+       if (tracking && !s->store_user) {
+               if (slab_empty(s))
+                       set_obj(s, "store_user", 1);
+               else
+                       fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
+       }
+       if (!tracking && s->store_user) {
+               if (slab_empty(s))
+                       set_obj(s, "store_user", 0);
+               else
+                       fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
+       }
+       if (tracing && !s->trace) {
+               if (slabs == 1)
+                       set_obj(s, "trace", 1);
+               else
+                       fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
+       }
+       if (!tracing && s->trace)
+               set_obj(s, "trace", 1);
+}
+
+static void totals(void)
+{
+       struct slabinfo *s;
+
+       int used_slabs = 0;
+       char b1[20], b2[20], b3[20], b4[20];
+       unsigned long long max = 1ULL << 63;
+
+       /* Object size */
+       unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
+
+       /* Number of partial slabs in a slabcache */
+       unsigned long long min_partial = max, max_partial = 0,
+                               avg_partial, total_partial = 0;
+
+       /* Number of slabs in a slab cache */
+       unsigned long long min_slabs = max, max_slabs = 0,
+                               avg_slabs, total_slabs = 0;
+
+       /* Size of the whole slab */
+       unsigned long long min_size = max, max_size = 0,
+                               avg_size, total_size = 0;
+
+       /* Bytes used for object storage in a slab */
+       unsigned long long min_used = max, max_used = 0,
+                               avg_used, total_used = 0;
+
+       /* Waste: Bytes used for alignment and padding */
+       unsigned long long min_waste = max, max_waste = 0,
+                               avg_waste, total_waste = 0;
+       /* Number of objects in a slab */
+       unsigned long long min_objects = max, max_objects = 0,
+                               avg_objects, total_objects = 0;
+       /* Waste per object */
+       unsigned long long min_objwaste = max,
+                               max_objwaste = 0, avg_objwaste,
+                               total_objwaste = 0;
+
+       /* Memory per object */
+       unsigned long long min_memobj = max,
+                               max_memobj = 0, avg_memobj,
+                               total_objsize = 0;
+
+       /* Percentage of partial slabs per slab */
+       unsigned long min_ppart = 100, max_ppart = 0,
+                               avg_ppart, total_ppart = 0;
+
+       /* Number of objects in partial slabs */
+       unsigned long min_partobj = max, max_partobj = 0,
+                               avg_partobj, total_partobj = 0;
+
+       /* Percentage of partial objects of all objects in a slab */
+       unsigned long min_ppartobj = 100, max_ppartobj = 0,
+                               avg_ppartobj, total_ppartobj = 0;
+
+
+       for (s = slabinfo; s < slabinfo + slabs; s++) {
+               unsigned long long size;
+               unsigned long used;
+               unsigned long long wasted;
+               unsigned long long objwaste;
+               unsigned long percentage_partial_slabs;
+               unsigned long percentage_partial_objs;
+
+               if (!s->slabs || !s->objects)
+                       continue;
+
+               used_slabs++;
+
+               size = slab_size(s);
+               used = s->objects * s->object_size;
+               wasted = size - used;
+               objwaste = s->slab_size - s->object_size;
+
+               percentage_partial_slabs = s->partial * 100 / s->slabs;
+               if (percentage_partial_slabs > 100)
+                       percentage_partial_slabs = 100;
+
+               percentage_partial_objs = s->objects_partial * 100
+                                                       / s->objects;
+
+               if (percentage_partial_objs > 100)
+                       percentage_partial_objs = 100;
+
+               if (s->object_size < min_objsize)
+                       min_objsize = s->object_size;
+               if (s->partial < min_partial)
+                       min_partial = s->partial;
+               if (s->slabs < min_slabs)
+                       min_slabs = s->slabs;
+               if (size < min_size)
+                       min_size = size;
+               if (wasted < min_waste)
+                       min_waste = wasted;
+               if (objwaste < min_objwaste)
+                       min_objwaste = objwaste;
+               if (s->objects < min_objects)
+                       min_objects = s->objects;
+               if (used < min_used)
+                       min_used = used;
+               if (s->objects_partial < min_partobj)
+                       min_partobj = s->objects_partial;
+               if (percentage_partial_slabs < min_ppart)
+                       min_ppart = percentage_partial_slabs;
+               if (percentage_partial_objs < min_ppartobj)
+                       min_ppartobj = percentage_partial_objs;
+               if (s->slab_size < min_memobj)
+                       min_memobj = s->slab_size;
+
+               if (s->object_size > max_objsize)
+                       max_objsize = s->object_size;
+               if (s->partial > max_partial)
+                       max_partial = s->partial;
+               if (s->slabs > max_slabs)
+                       max_slabs = s->slabs;
+               if (size > max_size)
+                       max_size = size;
+               if (wasted > max_waste)
+                       max_waste = wasted;
+               if (objwaste > max_objwaste)
+                       max_objwaste = objwaste;
+               if (s->objects > max_objects)
+                       max_objects = s->objects;
+               if (used > max_used)
+                       max_used = used;
+               if (s->objects_partial > max_partobj)
+                       max_partobj = s->objects_partial;
+               if (percentage_partial_slabs > max_ppart)
+                       max_ppart = percentage_partial_slabs;
+               if (percentage_partial_objs > max_ppartobj)
+                       max_ppartobj = percentage_partial_objs;
+               if (s->slab_size > max_memobj)
+                       max_memobj = s->slab_size;
+
+               total_partial += s->partial;
+               total_slabs += s->slabs;
+               total_size += size;
+               total_waste += wasted;
+
+               total_objects += s->objects;
+               total_used += used;
+               total_partobj += s->objects_partial;
+               total_ppart += percentage_partial_slabs;
+               total_ppartobj += percentage_partial_objs;
+
+               total_objwaste += s->objects * objwaste;
+               total_objsize += s->objects * s->slab_size;
+       }
+
+       if (!total_objects) {
+               printf("No objects\n");
+               return;
+       }
+       if (!used_slabs) {
+               printf("No slabs\n");
+               return;
+       }
+
+       /* Per slab averages */
+       avg_partial = total_partial / used_slabs;
+       avg_slabs = total_slabs / used_slabs;
+       avg_size = total_size / used_slabs;
+       avg_waste = total_waste / used_slabs;
+
+       avg_objects = total_objects / used_slabs;
+       avg_used = total_used / used_slabs;
+       avg_partobj = total_partobj / used_slabs;
+       avg_ppart = total_ppart / used_slabs;
+       avg_ppartobj = total_ppartobj / used_slabs;
+
+       /* Per object object sizes */
+       avg_objsize = total_used / total_objects;
+       avg_objwaste = total_objwaste / total_objects;
+       avg_partobj = total_partobj * 100 / total_objects;
+       avg_memobj = total_objsize / total_objects;
+
+       printf("Slabcache Totals\n");
+       printf("----------------\n");
+       printf("Slabcaches : %3d      Aliases  : %3d->%-3d Active: %3d\n",
+                       slabs, aliases, alias_targets, used_slabs);
+
+       store_size(b1, total_size);store_size(b2, total_waste);
+       store_size(b3, total_waste * 100 / total_used);
+       printf("Memory used: %6s   # Loss   : %6s   MRatio:%6s%%\n", b1, b2, b3);
+
+       store_size(b1, total_objects);store_size(b2, total_partobj);
+       store_size(b3, total_partobj * 100 / total_objects);
+       printf("# Objects  : %6s   # PartObj: %6s   ORatio:%6s%%\n", b1, b2, b3);
+
+       printf("\n");
+       printf("Per Cache    Average         Min         Max       Total\n");
+       printf("---------------------------------------------------------\n");
+
+       store_size(b1, avg_objects);store_size(b2, min_objects);
+       store_size(b3, max_objects);store_size(b4, total_objects);
+       printf("#Objects  %10s  %10s  %10s  %10s\n",
+                       b1,     b2,     b3,     b4);
+
+       store_size(b1, avg_slabs);store_size(b2, min_slabs);
+       store_size(b3, max_slabs);store_size(b4, total_slabs);
+       printf("#Slabs    %10s  %10s  %10s  %10s\n",
+                       b1,     b2,     b3,     b4);
+
+       store_size(b1, avg_partial);store_size(b2, min_partial);
+       store_size(b3, max_partial);store_size(b4, total_partial);
+       printf("#PartSlab %10s  %10s  %10s  %10s\n",
+                       b1,     b2,     b3,     b4);
+       store_size(b1, avg_ppart);store_size(b2, min_ppart);
+       store_size(b3, max_ppart);
+       store_size(b4, total_partial * 100  / total_slabs);
+       printf("%%PartSlab%10s%% %10s%% %10s%% %10s%%\n",
+                       b1,     b2,     b3,     b4);
+
+       store_size(b1, avg_partobj);store_size(b2, min_partobj);
+       store_size(b3, max_partobj);
+       store_size(b4, total_partobj);
+       printf("PartObjs  %10s  %10s  %10s  %10s\n",
+                       b1,     b2,     b3,     b4);
+
+       store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
+       store_size(b3, max_ppartobj);
+       store_size(b4, total_partobj * 100 / total_objects);
+       printf("%% PartObj%10s%% %10s%% %10s%% %10s%%\n",
+                       b1,     b2,     b3,     b4);
+
+       store_size(b1, avg_size);store_size(b2, min_size);
+       store_size(b3, max_size);store_size(b4, total_size);
+       printf("Memory    %10s  %10s  %10s  %10s\n",
+                       b1,     b2,     b3,     b4);
+
+       store_size(b1, avg_used);store_size(b2, min_used);
+       store_size(b3, max_used);store_size(b4, total_used);
+       printf("Used      %10s  %10s  %10s  %10s\n",
+                       b1,     b2,     b3,     b4);
+
+       store_size(b1, avg_waste);store_size(b2, min_waste);
+       store_size(b3, max_waste);store_size(b4, total_waste);
+       printf("Loss      %10s  %10s  %10s  %10s\n",
+                       b1,     b2,     b3,     b4);
+
+       printf("\n");
+       printf("Per Object   Average         Min         Max\n");
+       printf("---------------------------------------------\n");
+
+       store_size(b1, avg_memobj);store_size(b2, min_memobj);
+       store_size(b3, max_memobj);
+       printf("Memory    %10s  %10s  %10s\n",
+                       b1,     b2,     b3);
+       store_size(b1, avg_objsize);store_size(b2, min_objsize);
+       store_size(b3, max_objsize);
+       printf("User      %10s  %10s  %10s\n",
+                       b1,     b2,     b3);
+
+       store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
+       store_size(b3, max_objwaste);
+       printf("Loss      %10s  %10s  %10s\n",
+                       b1,     b2,     b3);
+}
+
+static void sort_slabs(void)
+{
+       struct slabinfo *s1,*s2;
+
+       for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
+               for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
+                       int result;
+
+                       if (sort_size)
+                               result = slab_size(s1) < slab_size(s2);
+                       else if (sort_active)
+                               result = slab_activity(s1) < slab_activity(s2);
+                       else
+                               result = strcasecmp(s1->name, s2->name);
+
+                       if (show_inverted)
+                               result = -result;
+
+                       if (result > 0) {
+                               struct slabinfo t;
+
+                               memcpy(&t, s1, sizeof(struct slabinfo));
+                               memcpy(s1, s2, sizeof(struct slabinfo));
+                               memcpy(s2, &t, sizeof(struct slabinfo));
+                       }
+               }
+       }
+}
+
+static void sort_aliases(void)
+{
+       struct aliasinfo *a1,*a2;
+
+       for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
+               for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
+                       char *n1, *n2;
+
+                       n1 = a1->name;
+                       n2 = a2->name;
+                       if (show_alias && !show_inverted) {
+                               n1 = a1->ref;
+                               n2 = a2->ref;
+                       }
+                       if (strcasecmp(n1, n2) > 0) {
+                               struct aliasinfo t;
+
+                               memcpy(&t, a1, sizeof(struct aliasinfo));
+                               memcpy(a1, a2, sizeof(struct aliasinfo));
+                               memcpy(a2, &t, sizeof(struct aliasinfo));
+                       }
+               }
+       }
+}
+
+static void link_slabs(void)
+{
+       struct aliasinfo *a;
+       struct slabinfo *s;
+
+       for (a = aliasinfo; a < aliasinfo + aliases; a++) {
+
+               for (s = slabinfo; s < slabinfo + slabs; s++)
+                       if (strcmp(a->ref, s->name) == 0) {
+                               a->slab = s;
+                               s->refs++;
+                               break;
+                       }
+               if (s == slabinfo + slabs)
+                       fatal("Unresolved alias %s\n", a->ref);
+       }
+}
+
+static void alias(void)
+{
+       struct aliasinfo *a;
+       char *active = NULL;
+
+       sort_aliases();
+       link_slabs();
+
+       for(a = aliasinfo; a < aliasinfo + aliases; a++) {
+
+               if (!show_single_ref && a->slab->refs == 1)
+                       continue;
+
+               if (!show_inverted) {
+                       if (active) {
+                               if (strcmp(a->slab->name, active) == 0) {
+                                       printf(" %s", a->name);
+                                       continue;
+                               }
+                       }
+                       printf("\n%-12s <- %s", a->slab->name, a->name);
+                       active = a->slab->name;
+               }
+               else
+                       printf("%-20s -> %s\n", a->name, a->slab->name);
+       }
+       if (active)
+               printf("\n");
+}
+
+
+static void rename_slabs(void)
+{
+       struct slabinfo *s;
+       struct aliasinfo *a;
+
+       for (s = slabinfo; s < slabinfo + slabs; s++) {
+               if (*s->name != ':')
+                       continue;
+
+               if (s->refs > 1 && !show_first_alias)
+                       continue;
+
+               a = find_one_alias(s);
+
+               if (a)
+                       s->name = a->name;
+               else {
+                       s->name = "*";
+                       actual_slabs--;
+               }
+       }
+}
+
+static int slab_mismatch(char *slab)
+{
+       return regexec(&pattern, slab, 0, NULL, 0);
+}
+
+static void read_slab_dir(void)
+{
+       DIR *dir;
+       struct dirent *de;
+       struct slabinfo *slab = slabinfo;
+       struct aliasinfo *alias = aliasinfo;
+       char *p;
+       char *t;
+       int count;
+
+       if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
+               fatal("SYSFS support for SLUB not active\n");
+
+       dir = opendir(".");
+       while ((de = readdir(dir))) {
+               if (de->d_name[0] == '.' ||
+                       (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
+                               continue;
+               switch (de->d_type) {
+                  case DT_LNK:
+                       alias->name = strdup(de->d_name);
+                       count = readlink(de->d_name, buffer, sizeof(buffer));
+
+                       if (count < 0)
+                               fatal("Cannot read symlink %s\n", de->d_name);
+
+                       buffer[count] = 0;
+                       p = buffer + count;
+                       while (p > buffer && p[-1] != '/')
+                               p--;
+                       alias->ref = strdup(p);
+                       alias++;
+                       break;
+                  case DT_DIR:
+                       if (chdir(de->d_name))
+                               fatal("Unable to access slab %s\n", slab->name);
+                       slab->name = strdup(de->d_name);
+                       slab->alias = 0;
+                       slab->refs = 0;
+                       slab->aliases = get_obj("aliases");
+                       slab->align = get_obj("align");
+                       slab->cache_dma = get_obj("cache_dma");
+                       slab->cpu_slabs = get_obj("cpu_slabs");
+                       slab->destroy_by_rcu = get_obj("destroy_by_rcu");
+                       slab->hwcache_align = get_obj("hwcache_align");
+                       slab->object_size = get_obj("object_size");
+                       slab->objects = get_obj("objects");
+                       slab->objects_partial = get_obj("objects_partial");
+                       slab->objects_total = get_obj("objects_total");
+                       slab->objs_per_slab = get_obj("objs_per_slab");
+                       slab->order = get_obj("order");
+                       slab->partial = get_obj("partial");
+                       slab->partial = get_obj_and_str("partial", &t);
+                       decode_numa_list(slab->numa_partial, t);
+                       free(t);
+                       slab->poison = get_obj("poison");
+                       slab->reclaim_account = get_obj("reclaim_account");
+                       slab->red_zone = get_obj("red_zone");
+                       slab->sanity_checks = get_obj("sanity_checks");
+                       slab->slab_size = get_obj("slab_size");
+                       slab->slabs = get_obj_and_str("slabs", &t);
+                       decode_numa_list(slab->numa, t);
+                       free(t);
+                       slab->store_user = get_obj("store_user");
+                       slab->trace = get_obj("trace");
+                       slab->alloc_fastpath = get_obj("alloc_fastpath");
+                       slab->alloc_slowpath = get_obj("alloc_slowpath");
+                       slab->free_fastpath = get_obj("free_fastpath");
+                       slab->free_slowpath = get_obj("free_slowpath");
+                       slab->free_frozen= get_obj("free_frozen");
+                       slab->free_add_partial = get_obj("free_add_partial");
+                       slab->free_remove_partial = get_obj("free_remove_partial");
+                       slab->alloc_from_partial = get_obj("alloc_from_partial");
+                       slab->alloc_slab = get_obj("alloc_slab");
+                       slab->alloc_refill = get_obj("alloc_refill");
+                       slab->free_slab = get_obj("free_slab");
+                       slab->cpuslab_flush = get_obj("cpuslab_flush");
+                       slab->deactivate_full = get_obj("deactivate_full");
+                       slab->deactivate_empty = get_obj("deactivate_empty");
+                       slab->deactivate_to_head = get_obj("deactivate_to_head");
+                       slab->deactivate_to_tail = get_obj("deactivate_to_tail");
+                       slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
+                       slab->order_fallback = get_obj("order_fallback");
+                       chdir("..");
+                       if (slab->name[0] == ':')
+                               alias_targets++;
+                       slab++;
+                       break;
+                  default :
+                       fatal("Unknown file type %lx\n", de->d_type);
+               }
+       }
+       closedir(dir);
+       slabs = slab - slabinfo;
+       actual_slabs = slabs;
+       aliases = alias - aliasinfo;
+       if (slabs > MAX_SLABS)
+               fatal("Too many slabs\n");
+       if (aliases > MAX_ALIASES)
+               fatal("Too many aliases\n");
+}
+
+static void output_slabs(void)
+{
+       struct slabinfo *slab;
+
+       for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
+
+               if (slab->alias)
+                       continue;
+
+
+               if (show_numa)
+                       slab_numa(slab, 0);
+               else if (show_track)
+                       show_tracking(slab);
+               else if (validate)
+                       slab_validate(slab);
+               else if (shrink)
+                       slab_shrink(slab);
+               else if (set_debug)
+                       slab_debug(slab);
+               else if (show_ops)
+                       ops(slab);
+               else if (show_slab)
+                       slabcache(slab);
+               else if (show_report)
+                       report(slab);
+       }
+}
+
+struct option opts[] = {
+       { "aliases", 0, NULL, 'a' },
+       { "activity", 0, NULL, 'A' },
+       { "debug", 2, NULL, 'd' },
+       { "display-activity", 0, NULL, 'D' },
+       { "empty", 0, NULL, 'e' },
+       { "first-alias", 0, NULL, 'f' },
+       { "help", 0, NULL, 'h' },
+       { "inverted", 0, NULL, 'i'},
+       { "numa", 0, NULL, 'n' },
+       { "ops", 0, NULL, 'o' },
+       { "report", 0, NULL, 'r' },
+       { "shrink", 0, NULL, 's' },
+       { "slabs", 0, NULL, 'l' },
+       { "track", 0, NULL, 't'},
+       { "validate", 0, NULL, 'v' },
+       { "zero", 0, NULL, 'z' },
+       { "1ref", 0, NULL, '1'},
+       { NULL, 0, NULL, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+       int c;
+       int err;
+       char *pattern_source;
+
+       page_size = getpagesize();
+
+       while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS",
+                                               opts, NULL)) != -1)
+               switch (c) {
+               case '1':
+                       show_single_ref = 1;
+                       break;
+               case 'a':
+                       show_alias = 1;
+                       break;
+               case 'A':
+                       sort_active = 1;
+                       break;
+               case 'd':
+                       set_debug = 1;
+                       if (!debug_opt_scan(optarg))
+                               fatal("Invalid debug option '%s'\n", optarg);
+                       break;
+               case 'D':
+                       show_activity = 1;
+                       break;
+               case 'e':
+                       show_empty = 1;
+                       break;
+               case 'f':
+                       show_first_alias = 1;
+                       break;
+               case 'h':
+                       usage();
+                       return 0;
+               case 'i':
+                       show_inverted = 1;
+                       break;
+               case 'n':
+                       show_numa = 1;
+                       break;
+               case 'o':
+                       show_ops = 1;
+                       break;
+               case 'r':
+                       show_report = 1;
+                       break;
+               case 's':
+                       shrink = 1;
+                       break;
+               case 'l':
+                       show_slab = 1;
+                       break;
+               case 't':
+                       show_track = 1;
+                       break;
+               case 'v':
+                       validate = 1;
+                       break;
+               case 'z':
+                       skip_zero = 0;
+                       break;
+               case 'T':
+                       show_totals = 1;
+                       break;
+               case 'S':
+                       sort_size = 1;
+                       break;
+
+               default:
+                       fatal("%s: Invalid option '%c'\n", argv[0], optopt);
+
+       }
+
+       if (!show_slab && !show_alias && !show_track && !show_report
+               && !validate && !shrink && !set_debug && !show_ops)
+                       show_slab = 1;
+
+       if (argc > optind)
+               pattern_source = argv[optind];
+       else
+               pattern_source = ".*";
+
+       err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
+       if (err)
+               fatal("%s: Invalid pattern '%s' code %d\n",
+                       argv[0], pattern_source, err);
+       read_slab_dir();
+       if (show_alias)
+               alias();
+       else
+       if (show_totals)
+               totals();
+       else {
+               link_slabs();
+               rename_slabs();
+               sort_slabs();
+               output_slabs();
+       }
+       return 0;
+}
index b2b3c2d..7f06884 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",